diff --git a/.clang-format b/.clang-format index dcbe69f..46923aa 100644 --- a/.clang-format +++ b/.clang-format @@ -1,137 +1,238 @@ ---- -Language: Cpp -# BasedOnStyle: GNU -AccessModifierOffset: -2 -AlignAfterOpenBracket: Align -AlignConsecutiveMacros: false -AlignConsecutiveAssignments: false -AlignConsecutiveDeclarations: false -AlignEscapedNewlines: Right -AlignOperands: true -AlignTrailingComments: true -AllowAllArgumentsOnNextLine: true -AllowAllConstructorInitializersOnNextLine: true -AllowAllParametersOfDeclarationOnNextLine: true -AllowShortBlocksOnASingleLine: Never -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: All -AllowShortLambdasOnASingleLine: All -AllowShortIfStatementsOnASingleLine: Never -AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterDefinitionReturnType: All -AlwaysBreakAfterReturnType: AllDefinitions -AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: MultiLine -BinPackArguments: true -BinPackParameters: true -BraceWrapping: - AfterCaseLabel: true - AfterClass: true - AfterControlStatement: true - AfterEnum: true - AfterFunction: true - AfterNamespace: true - AfterObjCDeclaration: true - AfterStruct: true - AfterUnion: true - AfterExternBlock: true - BeforeCatch: true - BeforeElse: true - IndentBraces: true - SplitEmptyFunction: true - SplitEmptyRecord: true - SplitEmptyNamespace: true -BreakBeforeBinaryOperators: All -BreakBeforeBraces: GNU -BreakBeforeInheritanceComma: false -BreakInheritanceList: BeforeColon -BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: false -BreakConstructorInitializers: BeforeColon -BreakAfterJavaFieldAnnotations: false -BreakStringLiterals: true -ColumnLimit: 79 -CommentPragmas: '^ IWYU pragma:' -CompactNamespaces: false -ConstructorInitializerAllOnOneLineOrOnePerLine: false -ConstructorInitializerIndentWidth: 4 -ContinuationIndentWidth: 4 +# Commented out parameters are those with the same value as base LLVM style. +# We can uncomment them if we want to change their value, or enforce the +# chosen value in case the base style changes (last sync: Clang 17.0.6). +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: DontAlign +# AlignArrayOfStructures: None +# AlignConsecutiveAssignments: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# PadOperators: true +# AlignConsecutiveBitFields: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# PadOperators: false +# AlignConsecutiveDeclarations: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# PadOperators: false +# AlignConsecutiveMacros: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# PadOperators: false +# AlignConsecutiveShortCaseStatements: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCaseColons: false +# AlignEscapedNewlines: Right +AlignOperands: DontAlign +AlignTrailingComments: + Kind: Never + OverEmptyLines: 0 +# AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: false +# AllowShortBlocksOnASingleLine: Never +# AllowShortCaseLabelsOnASingleLine: false +# AllowShortEnumsOnASingleLine: true +# AllowShortFunctionsOnASingleLine: All +# AllowShortIfStatementsOnASingleLine: Never +# AllowShortLambdasOnASingleLine: All +# AllowShortLoopsOnASingleLine: false +# AlwaysBreakAfterDefinitionReturnType: None +# AlwaysBreakAfterReturnType: None +# AlwaysBreakBeforeMultilineStrings: false +# AlwaysBreakTemplateDeclarations: MultiLine +# AttributeMacros: +# - __capability +# BinPackArguments: true +# BinPackParameters: true +# BitFieldColonSpacing: Both +# BraceWrapping: +# AfterCaseLabel: false +# AfterClass: false +# AfterControlStatement: Never +# AfterEnum: false +# AfterFunction: false +# AfterNamespace: false +# AfterObjCDeclaration: false +# AfterStruct: false +# AfterUnion: false +# AfterExternBlock: false +# BeforeCatch: false +# BeforeElse: false +# BeforeLambdaBody: false +# BeforeWhile: false +# IndentBraces: false +# SplitEmptyFunction: true +# SplitEmptyRecord: true +# SplitEmptyNamespace: true +# BreakAfterAttributes: Never +# BreakAfterJavaFieldAnnotations: false +# BreakArrays: true +# BreakBeforeBinaryOperators: None +# BreakBeforeBraces: Attach +# BreakBeforeConceptDeclarations: Always +# BreakBeforeInlineASMColon: OnlyMultiline +# BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +# BreakInheritanceList: BeforeColon +# BreakStringLiterals: true +ColumnLimit: 0 +# CommentPragmas: '^ IWYU pragma:' +# CompactNamespaces: false +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 8 Cpp11BracedListStyle: false -DeriveLineEnding: true -DerivePointerAlignment: false -DisableFormat: false -ExperimentalAutoDetectBinPacking: false -FixNamespaceComments: false -ForEachMacros: - - foreach - - Q_FOREACH - - BOOST_FOREACH -IncludeBlocks: Preserve +# DerivePointerAlignment: false +# DisableFormat: false +# EmptyLineAfterAccessModifier: Never +# EmptyLineBeforeAccessModifier: LogicalBlock +# ExperimentalAutoDetectBinPacking: false +# FixNamespaceComments: true +# ForEachMacros: +# - foreach +# - Q_FOREACH +# - BOOST_FOREACH +# IfMacros: +# - KJ_IF_MAYBE +# IncludeBlocks: Preserve IncludeCategories: - - Regex: '^"(llvm|llvm-c|clang|clang-c)/' - Priority: 2 - SortPriority: 0 - - Regex: '^(<|"(gtest|gmock|isl|json)/)' - Priority: 3 - SortPriority: 0 - - Regex: '.*' - Priority: 1 - SortPriority: 0 -IncludeIsMainRegex: '(Test)?$' -IncludeIsMainSourceRegex: '' -IndentCaseLabels: false -IndentGotoLabels: true -IndentPPDirectives: None -IndentWidth: 2 -IndentWrappedFunctionNames: false -JavaScriptQuotes: Leave -JavaScriptWrapImports: true -KeepEmptyLinesAtTheStartOfBlocks: true -MacroBlockBegin: '' -MacroBlockEnd: '' -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -ObjCBinPackProtocolList: Auto -ObjCBlockIndentWidth: 2 -ObjCSpaceAfterProperty: false -ObjCSpaceBeforeProtocolList: true -PenaltyBreakAssignment: 2 -PenaltyBreakBeforeFirstCallParameter: 19 -PenaltyBreakComment: 300 -PenaltyBreakFirstLessLess: 120 -PenaltyBreakString: 1000 -PenaltyBreakTemplateDeclaration: 10 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 60 -PointerAlignment: Right -ReflowComments: true -SortIncludes: true -SortUsingDeclarations: true -SpaceAfterCStyleCast: false -SpaceAfterLogicalNot: false -SpaceAfterTemplateKeyword: true -SpaceBeforeAssignmentOperators: true -SpaceBeforeCpp11BracedList: false -SpaceBeforeCtorInitializerColon: true -SpaceBeforeInheritanceColon: true -SpaceBeforeParens: Always -SpaceBeforeRangeBasedForLoopColon: true -SpaceInEmptyBlock: false -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 1 -SpacesInAngles: false -SpacesInConditionalStatement: false -SpacesInContainerLiterals: true -SpacesInCStyleCastParentheses: false -SpacesInParentheses: false -SpacesInSquareBrackets: false -SpaceBeforeSquareBrackets: false -Standard: c++03 -StatementMacros: - - Q_UNUSED - - QT_REQUIRE_VERSION -TabWidth: 8 -UseCRLF: false -UseTab: Never -... - + - Regex: ^".*"$ + Priority: 1 + - Regex: ^<.*\.h>$ + Priority: 2 + - Regex: ^<.*>$ + Priority: 3 +# IncludeIsMainRegex: (Test)?$ +# IncludeIsMainSourceRegex: '' +# IndentAccessModifiers: false +# IndentCaseBlocks: false +IndentCaseLabels: true +# IndentExternBlock: AfterExternBlock +# IndentGotoLabels: true +# IndentPPDirectives: None +# IndentRequiresClause: true +IndentWidth: 4 +# IndentWrappedFunctionNames: false +# InsertBraces: false +# InsertNewlineAtEOF: false +# InsertTrailingCommas: None +# IntegerLiteralSeparator: +# Binary: 0 +# BinaryMinDigits: 0 +# Decimal: 0 +# DecimalMinDigits: 0 +# Hex: 0 +# HexMinDigits: 0 +JavaImportGroups: + - org.godotengine + - android + - androidx + - com.android + - com.google + - java + - javax +# JavaScriptQuotes: Leave +# JavaScriptWrapImports: true +# KeepEmptyLinesAtEOF: false +KeepEmptyLinesAtTheStartOfBlocks: false +# LambdaBodyIndentation: Signature +# Language: Cpp +# LineEnding: DeriveLF +# MacroBlockBegin: '' +# MacroBlockEnd: '' +# MaxEmptyLinesToKeep: 1 +# NamespaceIndentation: None +# ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 4 +# ObjCBreakBeforeNestedBlockParam: true +# ObjCSpaceAfterProperty: false +# ObjCSpaceBeforeProtocolList: true +# PPIndentWidth: -1 +PackConstructorInitializers: NextLine +# PenaltyBreakAssignment: 2 +# PenaltyBreakBeforeFirstCallParameter: 19 +# PenaltyBreakComment: 300 +# PenaltyBreakFirstLessLess: 120 +# PenaltyBreakOpenParenthesis: 0 +# PenaltyBreakString: 1000 +# PenaltyBreakTemplateDeclaration: 10 +# PenaltyExcessCharacter: 1000000 +# PenaltyIndentedWhitespace: 0 +# PenaltyReturnTypeOnItsOwnLine: 60 +# PointerAlignment: Right +# QualifierAlignment: Leave +# ReferenceAlignment: Pointer +# ReflowComments: true +# RemoveBracesLLVM: false +# RemoveParentheses: Leave +RemoveSemicolon: true +# RequiresClausePosition: OwnLine +# RequiresExpressionIndentation: OuterScope +# SeparateDefinitionBlocks: Leave +# ShortNamespaceLines: 1 +# SortIncludes: CaseSensitive +# SortJavaStaticImport: Before +# SortUsingDeclarations: LexicographicNumeric +# SpaceAfterCStyleCast: false +# SpaceAfterLogicalNot: false +# SpaceAfterTemplateKeyword: true +# SpaceAroundPointerQualifiers: Default +# SpaceBeforeAssignmentOperators: true +# SpaceBeforeCaseColon: false +# SpaceBeforeCpp11BracedList: false +# SpaceBeforeCtorInitializerColon: true +# SpaceBeforeInheritanceColon: true +# SpaceBeforeJsonColon: false +# SpaceBeforeParens: ControlStatements +# SpaceBeforeParensOptions: +# AfterControlStatements: true +# AfterForeachMacros: true +# AfterFunctionDeclarationName: false +# AfterFunctionDefinitionName: false +# AfterIfMacros: true +# AfterOverloadedOperator: false +# AfterRequiresInClause: false +# AfterRequiresInExpression: false +# BeforeNonEmptyParentheses: false +# SpaceBeforeRangeBasedForLoopColon: true +# SpaceBeforeSquareBrackets: false +# SpaceInEmptyBlock: false +# SpacesBeforeTrailingComments: 1 +# SpacesInAngles: Never +# SpacesInContainerLiterals: true +SpacesInLineCommentPrefix: + Minimum: 0 # We want a minimum of 1 for comments, but allow 0 for disabled code. + Maximum: -1 +# SpacesInParens: Never +# SpacesInParensOptions: +# InConditionalStatements: false +# InCStyleCasts: false +# InEmptyParentheses: false +# Other: false +# SpacesInSquareBrackets: false +Standard: c++20 +# StatementAttributeLikeMacros: +# - Q_EMIT +# StatementMacros: +# - Q_UNUSED +# - QT_REQUIRE_VERSION +TabWidth: 4 +UseTab: Always +# VerilogBreakBetweenInstancePorts: true +# WhitespaceSensitiveMacros: +# - BOOST_PP_STRINGIZE +# - CF_SWIFT_NAME +# - NS_SWIFT_NAME +# - PP_STRINGIZE +# - STRINGIZE diff --git a/.clang-format-ignore b/.clang-format-ignore new file mode 100644 index 0000000..428102f --- /dev/null +++ b/.clang-format-ignore @@ -0,0 +1,4 @@ +*/*/*.json +*/*/*.m +*/*/*/*.m +include/json.hpp \ No newline at end of file diff --git a/.github/license_header.txt b/.github/license_header.txt new file mode 100644 index 0000000..c4807b3 --- /dev/null +++ b/.github/license_header.txt @@ -0,0 +1,3 @@ +Copyright (C) 2024 Analog Devices, Inc. + +SPDX short identifier: ADIBSD OR GPL-2.0-or-later \ No newline at end of file diff --git a/.github/workflows/.pre-commit-config.yaml b/.github/workflows/.pre-commit-config.yaml deleted file mode 100644 index 2e5f622..0000000 --- a/.github/workflows/.pre-commit-config.yaml +++ /dev/null @@ -1,12 +0,0 @@ -repos: -- repo: https://github.com/Lucas-C/pre-commit-hooks - rev: v1.5.1 - hooks: - - id: insert-license - files: bindings\/python\/genalyzer\/.*\.py$ - args: - - --license-filepath - - .github/license_header.txt - - --use-current-year - - --no-extra-eol - - --detect-license-in-X-top-lines=3 \ No newline at end of file diff --git a/.github/workflows/license_header.txt b/.github/workflows/license_header.txt deleted file mode 100644 index f3eb502..0000000 --- a/.github/workflows/license_header.txt +++ /dev/null @@ -1,3 +0,0 @@ -Copyright (C) 2024 Analog Devices, Inc. - -SPDX short identifier: ADIBSD \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fce8567..034f019 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -161,3 +161,29 @@ jobs: pip install ".[tools]" python -m pytest -vs tests for f in examples/*.py; do python "$f"; done + + Lint: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: [3.8, 3.9, "3.10"] + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + bash ./.github/scripts/install_dependencies.sh + pip install -r requirements_test.txt + + - name: Lint + run: | + pre-commit run --all-files 2> /dev/null + ec=$? + git diff -U0 > log.txt && cat log.txt + exit $ec \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..7ed4f6c --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,34 @@ +repos: +- repo: https://github.com/Lucas-C/pre-commit-hooks + rev: v1.5.1 + hooks: + - id: insert-license + files: bindings\/python\/genalyzer\/.*\.py$ + args: + - --license-filepath + - .github/license_header.txt + - --use-current-year + - --no-extra-eol + - --detect-license-in-X-top-lines=3 + - id: insert-license + files: ^(?!doc\/|tests\/|examples\/|include\/json\.hpp$).*\.((hpp|h|cpp|c))$ + args: + - --comment-style + - // + - --license-filepath + - .github/license_header.txt + - --use-current-year + - --no-extra-eol + - --detect-license-in-X-top-lines=3 +- repo: https://github.com/cmake-lint/cmake-lint + rev: 1.4.3 + hooks: + - id: cmakelint + args: + - --linelength=200 + - --filter=-readability/mixedcase,-package/consistency +- repo: https://github.com/pre-commit/mirrors-clang-format + rev: v19.1.5 + hooks: + - id: clang-format + files: ^(?!doc\/|tests\/|examples\/).*\.((hpp|h|cpp|c))$ \ No newline at end of file diff --git a/bindings/c/include/cgenalyzer.h b/bindings/c/include/cgenalyzer.h index 4881829..f43d6e4 100644 --- a/bindings/c/include/cgenalyzer.h +++ b/bindings/c/include/cgenalyzer.h @@ -1,25 +1,6 @@ -/* - * cgenalyzer - genalyzer API header file - * - * Copyright (C) 2022 Analog Devices, Inc. - * Author: Peter Derounian - * - * 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. - * */ - - +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef CGENALYZER_H #define CGENALYZER_H @@ -30,10 +11,10 @@ /** * \mainpage Genalyzer Library API Documentation * \section Overview - * The Genalyzer Library provides analysis routines for data converter testing. The - * library contains routines that analyze waveforms, FFTs, and the output of the traditional code - * density tests: histogram, DNL, and INL. In addition, the library provides basic signal - * generation and processing utilties. + * The Genalyzer Library provides analysis routines for data converter testing. + * The library contains routines that analyze waveforms, FFTs, and the output of + * the traditional code density tests: histogram, DNL, and INL. In addition, + * the library provides basic signal generation and processing utilties. * \section AnalysisRoutines Analysis Routines * The library provides the following types of analysis: * \li \ref gn_dnl_analysis "DNL Analysis" @@ -41,10 +22,11 @@ * \li \ref gn_hist_analysis "Histogram Analysis" * \li \ref gn_inl_analysis "INL Analysis" * \li \ref gn_wf_analysis "Waveform Analysis" - * - * Each analysis routine returns results by filling a Keys array (rkeys) and a corresponding Values - * array (rvalues). Together, rkeys and rvalues represent a set of key-value result pairs: - * rkeys[0] corresponds to rvalues[0], rkeys[1] to rvalues[1], and so on. + * + * Each analysis routine returns results by filling a Keys array (rkeys) and a + * corresponding Values array (rvalues). Together, rkeys and rvalues represent + * a set of key-value result pairs: rkeys[0] corresponds to rvalues[0], rkeys[1] + * to rvalues[1], and so on. */ /* Enumerations */ @@ -61,99 +43,100 @@ extern "C" { * @brief GnAnalysisType enumerates analysis types */ typedef enum GnAnalysisType { - GnAnalysisTypeDNL, ///< DNL (differential nonlinearity) - GnAnalysisTypeFourier, ///< Fourier (FFT) - GnAnalysisTypeHistogram, ///< Histogram - GnAnalysisTypeINL, ///< INL (integral nonlinearity) - GnAnalysisTypeWaveform ///< Waveform - } GnAnalysisType; + GnAnalysisTypeDNL, ///< DNL (differential nonlinearity) + GnAnalysisTypeFourier, ///< Fourier (FFT) + GnAnalysisTypeHistogram, ///< Histogram + GnAnalysisTypeINL, ///< INL (integral nonlinearity) + GnAnalysisTypeWaveform ///< Waveform +} GnAnalysisType; /** * @brief GnCodeFormat enumerates binary code formats */ typedef enum GnCodeFormat { - GnCodeFormatOffsetBinary, ///< Offset Binary - GnCodeFormatTwosComplement ///< Two's Complement - } GnCodeFormat; + GnCodeFormatOffsetBinary, ///< Offset Binary + GnCodeFormatTwosComplement ///< Two's Complement +} GnCodeFormat; /** * @brief GnDnlSignal enumerates signal types for which DNL can be computed */ typedef enum GnDnlSignal { - GnDnlSignalRamp, ///< Ramp - GnDnlSignalTone ///< Tone (Sinusoid) - } GnDnlSignal; + GnDnlSignalRamp, ///< Ramp + GnDnlSignalTone ///< Tone (Sinusoid) +} GnDnlSignal; /** * @brief GnFACompTag enumerates Fourier analysis component tags */ typedef enum GnFACompTag { - GnFACompTagDC, ///< DC component (always Bin 0) - GnFACompTagSignal, ///< Signal component - GnFACompTagHD, ///< Harmonic distortion - GnFACompTagIMD, ///< Intermodulation distortion - GnFACompTagILOS, ///< Interleaving offset component - GnFACompTagILGT, ///< Interleaving gain/timing/BW component - GnFACompTagCLK, ///< Clock component - GnFACompTagUserDist, ///< User-designated distortion - GnFACompTagNoise ///< Noise component (e.g. WorstOther) - } GnFACompTag; + GnFACompTagDC, ///< DC component (always Bin 0) + GnFACompTagSignal, ///< Signal component + GnFACompTagHD, ///< Harmonic distortion + GnFACompTagIMD, ///< Intermodulation distortion + GnFACompTagILOS, ///< Interleaving offset component + GnFACompTagILGT, ///< Interleaving gain/timing/BW component + GnFACompTagCLK, ///< Clock component + GnFACompTagUserDist, ///< User-designated distortion + GnFACompTagNoise ///< Noise component (e.g. WorstOther) +} GnFACompTag; /** - * @brief GnFASsb enumerates the component categories for which the number of single side bins - * (SSB) can be set + * @brief GnFASsb enumerates the component categories for which the number of + * single side bins (SSB) can be set */ typedef enum GnFASsb { - GnFASsbDefault, ///< Default SSB (applies to auto-generated components) - GnFASsbDC, ///< SSB for DC component - GnFASsbSignal, ///< SSB for Signal components - GnFASsbWO, ///< SSB for WorstOther components - } GnFASsb; + GnFASsbDefault, ///< Default SSB (applies to auto-generated components) + GnFASsbDC, ///< SSB for DC component + GnFASsbSignal, ///< SSB for Signal components + GnFASsbWO, ///< SSB for WorstOther components +} GnFASsb; /** * @brief GnFreqAxisFormat enumerates frequency axis formats */ typedef enum GnFreqAxisFormat { - GnFreqAxisFormatBins, ///< Bins - GnFreqAxisFormatFreq, ///< Frequency - GnFreqAxisFormatNorm ///< Normalized - } GnFreqAxisFormat; + GnFreqAxisFormatBins, ///< Bins + GnFreqAxisFormatFreq, ///< Frequency + GnFreqAxisFormatNorm ///< Normalized +} GnFreqAxisFormat; /** * @brief GnFreqAxisType enumerates frequency axis types */ typedef enum GnFreqAxisType { - GnFreqAxisTypeDcCenter, ///< DC centered, e.g. [-fs/2, fs/2) (complex FFT only) - GnFreqAxisTypeDcLeft, ///< DC on left, e.g. [0, fs) (complex FFT only) - GnFreqAxisTypeReal ///< Real axis, e.g. [0, fs/2] (real FFT only) - } GnFreqAxisType; + GnFreqAxisTypeDcCenter, ///< DC centered, e.g. [-fs/2, fs/2) (complex FFT + ///< only) + GnFreqAxisTypeDcLeft, ///< DC on left, e.g. [0, fs) (complex FFT only) + GnFreqAxisTypeReal ///< Real axis, e.g. [0, fs/2] (real FFT only) +} GnFreqAxisType; /** * @brief GnInlLineFit enumerates INL line fitting options */ typedef enum GnInlLineFit { - GnInlLineFitBestFit, ///< Best fit - GnInlLineFitEndFit, ///< End fit - GnInlLineFitNoFit ///< No fit - } GnInlLineFit; + GnInlLineFitBestFit, ///< Best fit + GnInlLineFitEndFit, ///< End fit + GnInlLineFitNoFit ///< No fit +} GnInlLineFit; /** * @brief GnRfftScale enumerates real FFT scaling options */ typedef enum GnRfftScale { - GnRfftScaleDbfsDc, ///< Full-scale sinusoid measures -3 dBFS - GnRfftScaleDbfsSin, ///< Full-scale sinusoid measures 0 dBFS - GnRfftScaleNative ///< Full-scale sinusoid measures -6 dBFS - } GnRfftScale; + GnRfftScaleDbfsDc, ///< Full-scale sinusoid measures -3 dBFS + GnRfftScaleDbfsSin, ///< Full-scale sinusoid measures 0 dBFS + GnRfftScaleNative ///< Full-scale sinusoid measures -6 dBFS +} GnRfftScale; /** * @brief GnWindow enumerates window functions */ typedef enum GnWindow { - GnWindowBlackmanHarris, ///< Blackman-Harris - GnWindowHann, ///< Hann ("Hanning") - GnWindowNoWindow ///< No window (Rectangular) - } GnWindow; + GnWindowBlackmanHarris, ///< Blackman-Harris + GnWindowHann, ///< Hann ("Hanning") + GnWindowNoWindow ///< No window (Rectangular) +} GnWindow; /** @} Enumerations */ @@ -172,9 +155,8 @@ extern "C" { #else #define __api __declspec(dllimport) #endif -#elif __GNUC__ >= 4 && !defined(MATLAB_MEX_FILE) \ - && !defined(MATLAB_LOADLIBRARY) -#define __api __attribute__ ((visibility ("default"))) +#elif __GNUC__ >= 4 && !defined(MATLAB_MEX_FILE) && !defined(MATLAB_LOADLIBRARY) +#define __api __attribute__((visibility("default"))) #else #define __api #endif @@ -187,40 +169,41 @@ extern "C" { /** * @brief gn_analysis_results_key_sizes * @return 0 on success, non-zero otherwise - * @details The library string termination setting determines whether or not a null terminator - * is included in the key sizes. See \ref gn_set_string_termination. + * @details The library string termination setting determines whether or not a + * null terminator is included in the key sizes. See \ref + * gn_set_string_termination. */ __api int gn_analysis_results_key_sizes( - size_t* key_sizes, ///< [out] Key size array pointer - size_t key_sizes_size, ///< [in] Key size array size - GnAnalysisType type ///< [in] Analysis type - ); + size_t *key_sizes, ///< [out] Key size array pointer + size_t key_sizes_size, ///< [in] Key size array size + GnAnalysisType type ///< [in] Analysis type +); /** * @brief gn_analysis_results_size * @return 0 on success, non-zero otherwise */ __api int gn_analysis_results_size( - size_t* size, ///< [out] Number of key-value result pairs - GnAnalysisType type ///< [in] Analysis type - ); + size_t *size, ///< [out] Number of key-value result pairs + GnAnalysisType type ///< [in] Analysis type +); /** * @brief gn_enum_value * @return 0 on success, non-zero otherwise */ -__api int gn_enum_value( - int* value, ///< [out] Underlying value of enumeration::enumerator - const char* enumeration, ///< [in] Enumeration name - const char* enumerator ///< [in] Enumerator name - ); +__api int +gn_enum_value(int *value, ///< [out] Underlying value of enumeration::enumerator + const char *enumeration, ///< [in] Enumeration name + const char *enumerator ///< [in] Enumerator name +); /** * @brief gn_error_check * @return Always returns 0 */ __api int gn_error_check( - bool* error ///< [out] true if an error has occurred; false otherwise + bool *error ///< [out] true if an error has occurred; false otherwise ); /** @@ -233,32 +216,31 @@ __api int gn_error_clear(); * @brief gn_error_string * @return 0 on success, non-zero otherwise */ -__api int gn_error_string( - char* buf, ///< [out] Pointer to character array - size_t size ///< [in] Size of character array - ); +__api int gn_error_string(char *buf, ///< [out] Pointer to character array + size_t size ///< [in] Size of character array +); /** * @brief gn_set_string_termination * @return Always returns 0 - * @details Some functions in this library return strings by filling character buffers (arrays) - * provided by the caller. This function sets a global library setting that determines whether or - * not strings should be null-terminated. If set to true, functions that return strings will - * write a '\0' as the last character. In addition, functions that return the size of a string - * will include the null terminator in the size. + * @details Some functions in this library return strings by filling character + * buffers (arrays) provided by the caller. This function sets a global library + * setting that determines whether or not strings should be null-terminated. If + * set to true, functions that return strings will write a '\0' as the last + * character. In addition, functions that return the size of a string will + * include the null terminator in the size. */ __api int gn_set_string_termination( - bool null_terminated ///< [in] If true, strings are terminated with '\0' + bool null_terminated ///< [in] If true, strings are terminated with '\0' ); /** * @brief gn_version_string * @return 0 on success, non-zero otherwise */ -__api int gn_version_string( - char* buf, ///< [in,out] Pointer to character array - size_t size ///< [in] Size of character array - ); +__api int gn_version_string(char *buf, ///< [in,out] Pointer to character array + size_t size ///< [in] Size of character array +); /** * \defgroup APIUtilityHelpers Helpers @@ -268,21 +250,21 @@ __api int gn_version_string( /** * @brief gn_error_string_size * @return Always returns 0 - * @details The library string termination setting determines whether or not a null terminator - * is included in the size. See \ref gn_set_string_termination. + * @details The library string termination setting determines whether or not a + * null terminator is included in the size. See \ref gn_set_string_termination. */ __api int gn_error_string_size( - size_t* size ///< [out] Number of characters in error string + size_t *size ///< [out] Number of characters in error string ); /** * @brief gn_version_string_size * @return Always returns 0 - * @details The library string termination setting determines whether or not a null terminator - * is included in the size. See \ref gn_set_string_termination. + * @details The library string termination setting determines whether or not a + * null terminator is included in the size. See \ref gn_set_string_termination. */ __api int gn_version_string_size( - size_t* size ///< [out] Number of characters in version string + size_t *size ///< [out] Number of characters in version string ); /** @} APIUtilityHelpers */ @@ -307,67 +289,61 @@ extern "C" { * @brief gn_abs * @return 0 on success, non-zero otherwise */ -__api int gn_abs( - double* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const double* in, ///< [in] Input array pointer - size_t in_size ///< [in] Input array size - ); +__api int gn_abs(double *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const double *in, ///< [in] Input array pointer + size_t in_size ///< [in] Input array size +); /** * @brief gn_angle * @return 0 on success, non-zero otherwise */ -__api int gn_angle( - double* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const double* in, ///< [in] Input array pointer - size_t in_size ///< [in] Input array size - ); +__api int gn_angle(double *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const double *in, ///< [in] Input array pointer + size_t in_size ///< [in] Input array size +); /** * @brief gn_db * @return 0 on success, non-zero otherwise */ -__api int gn_db( - double* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const double* in, ///< [in] Input array pointer - size_t in_size ///< [in] Input array size - ); +__api int gn_db(double *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const double *in, ///< [in] Input array pointer + size_t in_size ///< [in] Input array size +); /** * @brief gn_db10 * @return 0 on success, non-zero otherwise */ -__api int gn_db10( - double* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const double* in, ///< [in] Input array pointer - size_t in_size ///< [in] Input array size - ); +__api int gn_db10(double *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const double *in, ///< [in] Input array pointer + size_t in_size ///< [in] Input array size +); /** * @brief gn_db20 * @return 0 on success, non-zero otherwise */ -__api int gn_db20( - double* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const double* in, ///< [in] Input array pointer - size_t in_size ///< [in] Input array size - ); +__api int gn_db20(double *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const double *in, ///< [in] Input array pointer + size_t in_size ///< [in] Input array size +); /** * @brief gn_norm * @return 0 on success, non-zero otherwise */ -__api int gn_norm( - double* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const double* in, ///< [in] Input array pointer - size_t in_size ///< [in] Input array size - ); +__api int gn_norm(double *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const double *in, ///< [in] Input array pointer + size_t in_size ///< [in] Input array size +); /** @} ArrayOperations */ @@ -389,40 +365,38 @@ extern "C" { * @brief gn_code_axis * @return 0 on success, non-zero otherwise */ -__api int gn_code_axis( - double* out, ///< [out] Array pointer - size_t size, ///< [in] Array size - int n, ///< [in] Resolution - GnCodeFormat format ///< [in] Code format - ); +__api int gn_code_axis(double *out, ///< [out] Array pointer + size_t size, ///< [in] Array size + int n, ///< [in] Resolution + GnCodeFormat format ///< [in] Code format +); /** * @brief gn_code_axisx * @return 0 on success, non-zero otherwise */ -__api int gn_code_axisx( - double* out, ///< [out] Array pointer - size_t size, ///< [in] Array size - int64_t min, ///< [in] Min code - int64_t max ///< [in] Max code - ); +__api int gn_code_axisx(double *out, ///< [out] Array pointer + size_t size, ///< [in] Array size + int64_t min, ///< [in] Min code + int64_t max ///< [in] Max code +); /** * @brief gn_dnl * @return 0 on success, non-zero otherwise */ -__api int gn_dnl( - double* dnl, ///< [out] Output array pointer - size_t dnl_size, ///< [in] Output array size - const uint64_t* hist, ///< [in] Input array pointer - size_t hist_size, ///< [in] Input array size - GnDnlSignal type ///< [in] Signal type - ); +__api int gn_dnl(double *dnl, ///< [out] Output array pointer + size_t dnl_size, ///< [in] Output array size + const uint64_t *hist, ///< [in] Input array pointer + size_t hist_size, ///< [in] Input array size + GnDnlSignal type ///< [in] Signal type +); /** * @brief gn_dnl_analysis * @return 0 on success, non-zero otherwise - * @details The results contain the following key-value pairs (see general description of + * @details The results contain the following key-value pairs (see general + * description of * \ref AnalysisRoutines "Analysis Routines"). * *
Key Description @@ -434,140 +408,149 @@ __api int gn_dnl( *
max_index Index of first occurence of maximum value *
first_nm_index Index of first non-missing code *
last_nm_index Index of last non-missing code - *
nm_range Non-missing code range (1 + (last_nm_index - first_nm_index)) + *
nm_range Non-missing code range (1 + (last_nm_index - + * first_nm_index)) *
*/ -__api int gn_dnl_analysis( - char** rkeys, ///< [out] Result keys array pointer - size_t rkeys_size, ///< [in] Result keys array size - double* rvalues, ///< [out] Result values array pointer - size_t rvalues_size, ///< [in] Result values array size - const double* dnl, ///< [in] Input array pointer - size_t dnl_size ///< [in] Input array size - ); +__api int +gn_dnl_analysis(char **rkeys, ///< [out] Result keys array pointer + size_t rkeys_size, ///< [in] Result keys array size + double *rvalues, ///< [out] Result values array pointer + size_t rvalues_size, ///< [in] Result values array size + const double *dnl, ///< [in] Input array pointer + size_t dnl_size ///< [in] Input array size +); /** * @brief gn_hist16 * @return 0 on success, non-zero otherwise */ __api int gn_hist16( - uint64_t* hist, ///< [out] Histogram array pointer - size_t hist_size, ///< [in] Histogram array size - const int16_t* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - int n, ///< [in] Code width (i.e. ADC resolution) - GnCodeFormat format, ///< [in] Code format - bool preserve ///< [in] If true, hist is not cleared before computing the histogram - ); + uint64_t *hist, ///< [out] Histogram array pointer + size_t hist_size, ///< [in] Histogram array size + const int16_t *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + int n, ///< [in] Code width (i.e. ADC resolution) + GnCodeFormat format, ///< [in] Code format + bool preserve ///< [in] If true, hist is not cleared before computing the + ///< histogram +); /** * @brief gn_hist32 * @return 0 on success, non-zero otherwise */ __api int gn_hist32( - uint64_t* hist, ///< [out] Histogram array pointer - size_t hist_size, ///< [in] Histogram array size - const int32_t* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - int n, ///< [in] Code width (i.e. ADC resolution) - GnCodeFormat format, ///< [in] Code format - bool preserve ///< [in] If true, hist is not cleared before computing the histogram - ); + uint64_t *hist, ///< [out] Histogram array pointer + size_t hist_size, ///< [in] Histogram array size + const int32_t *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + int n, ///< [in] Code width (i.e. ADC resolution) + GnCodeFormat format, ///< [in] Code format + bool preserve ///< [in] If true, hist is not cleared before computing the + ///< histogram +); /** * @brief gn_hist64 * @return 0 on success, non-zero otherwise */ __api int gn_hist64( - uint64_t* hist, ///< [out] Histogram array pointer - size_t hist_size, ///< [in] Histogram array size - const int64_t* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - int n, ///< [in] Code width (i.e. ADC resolution) - GnCodeFormat format, ///< [in] Code format - bool preserve ///< [in] If true, hist is not cleared before computing the histogram - ); + uint64_t *hist, ///< [out] Histogram array pointer + size_t hist_size, ///< [in] Histogram array size + const int64_t *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + int n, ///< [in] Code width (i.e. ADC resolution) + GnCodeFormat format, ///< [in] Code format + bool preserve ///< [in] If true, hist is not cleared before computing the + ///< histogram +); /** * @brief gn_histx16 * @return 0 on success, non-zero otherwise */ __api int gn_histx16( - uint64_t* hist, ///< [out] Histogram array pointer - size_t hist_size, ///< [in] Histogram array size - const int16_t* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - int64_t min, ///< [in] Min code - int64_t max, ///< [in] Max code - bool preserve ///< [in] If true, hist is not cleared before computing the histogram - ); + uint64_t *hist, ///< [out] Histogram array pointer + size_t hist_size, ///< [in] Histogram array size + const int16_t *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + int64_t min, ///< [in] Min code + int64_t max, ///< [in] Max code + bool preserve ///< [in] If true, hist is not cleared before computing the + ///< histogram +); /** * @brief gn_histx32 * @return 0 on success, non-zero otherwise */ __api int gn_histx32( - uint64_t* hist, ///< [out] Histogram array pointer - size_t hist_size, ///< [in] Histogram array size - const int32_t* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - int64_t min, ///< [in] Min code - int64_t max, ///< [in] Max code - bool preserve ///< [in] If true, hist is not cleared before computing the histogram - ); + uint64_t *hist, ///< [out] Histogram array pointer + size_t hist_size, ///< [in] Histogram array size + const int32_t *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + int64_t min, ///< [in] Min code + int64_t max, ///< [in] Max code + bool preserve ///< [in] If true, hist is not cleared before computing the + ///< histogram +); /** * @brief gn_histx64 * @return 0 on success, non-zero otherwise */ __api int gn_histx64( - uint64_t* hist, ///< [out] Histogram array pointer - size_t hist_size, ///< [in] Histogram array size - const int64_t* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - int64_t min, ///< [in] Min code - int64_t max, ///< [in] Max code - bool preserve ///< [in] If true, hist is not cleared before computing the histogram - ); + uint64_t *hist, ///< [out] Histogram array pointer + size_t hist_size, ///< [in] Histogram array size + const int64_t *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + int64_t min, ///< [in] Min code + int64_t max, ///< [in] Max code + bool preserve ///< [in] If true, hist is not cleared before computing the + ///< histogram +); /** * @brief gn_hist_analysis * @return 0 on success, non-zero otherwise - * @details The results contain the following key-value pairs (see general description of + * @details The results contain the following key-value pairs (see general + * description of * \ref AnalysisRoutines "Analysis Routines"). * *
Key Description *
sum Sum of all histogram bins *
first_nz_index First non-zero bin *
last_nz_index Last non-zero bin - *
nz_range Non-zero bin range (1 + (last_nz_index - first_nz_index)) + *
nz_range Non-zero bin range (1 + (last_nz_index - + * first_nz_index)) *
*/ -__api int gn_hist_analysis( - char** rkeys, ///< [out] Result keys array pointer - size_t rkeys_size, ///< [in] Result keys array size - double* rvalues, ///< [out] Result values array pointer - size_t rvalues_size, ///< [in] Result values array size - const uint64_t* hist, ///< [in] Input array pointer - size_t hist_size ///< [in] Input array size - ); +__api int +gn_hist_analysis(char **rkeys, ///< [out] Result keys array pointer + size_t rkeys_size, ///< [in] Result keys array size + double *rvalues, ///< [out] Result values array pointer + size_t rvalues_size, ///< [in] Result values array size + const uint64_t *hist, ///< [in] Input array pointer + size_t hist_size ///< [in] Input array size +); /** * @brief gn_inl * @return 0 on success, non-zero otherwise */ -__api int gn_inl( - double* inl, ///< [out] Output array pointer - size_t inl_size, ///< [in] Output array size - const double* dnl, ///< [in] Input array pointer - size_t dnl_size, ///< [in] Input array size - GnInlLineFit fit ///< [in] Line fit type - ); +__api int gn_inl(double *inl, ///< [out] Output array pointer + size_t inl_size, ///< [in] Output array size + const double *dnl, ///< [in] Input array pointer + size_t dnl_size, ///< [in] Input array size + GnInlLineFit fit ///< [in] Line fit type +); /** * @brief gn_inl_analysis * @return 0 on success, non-zero otherwise - * @details The results contain the following key-value pairs (see general description of + * @details The results contain the following key-value pairs (see general + * description of * \ref AnalysisRoutines "Analysis Routines"). * *
Key Description @@ -577,14 +560,14 @@ __api int gn_inl( *
max_index Index of first occurence of maximum value *
*/ -__api int gn_inl_analysis( - char** rkeys, ///< [out] Result keys array pointer - size_t rkeys_size, ///< [in] Result keys array size - double* rvalues, ///< [out] Result values array pointer - size_t rvalues_size, ///< [in] Result values array size - const double* inl, ///< [in] Input array pointer - size_t inl_size ///< [in] Input array size - ); +__api int +gn_inl_analysis(char **rkeys, ///< [out] Result keys array pointer + size_t rkeys_size, ///< [in] Result keys array size + double *rvalues, ///< [out] Result values array pointer + size_t rvalues_size, ///< [in] Result values array size + const double *inl, ///< [in] Input array pointer + size_t inl_size ///< [in] Input array size +); /** * \defgroup CodeDensityHelpers Helpers @@ -595,21 +578,19 @@ __api int gn_inl_analysis( * @brief gn_code_density_size * @return 0 on success, non-zero otherwise */ -__api int gn_code_density_size( - size_t* size, ///< [out] Output array size - int n, ///< [in] Code width (i.e. ADC resolution) - GnCodeFormat format ///< [in] Code format - ); +__api int gn_code_density_size(size_t *size, ///< [out] Output array size + int n, ///< [in] Code width (i.e. ADC resolution) + GnCodeFormat format ///< [in] Code format +); /** * @brief gn_code_densityx_size * @return 0 on success, non-zero otherwise */ -__api int gn_code_densityx_size( - size_t* size, ///< [out] Output array size - int64_t min, ///< [in] Min code - int64_t max ///< [in] Max code - ); +__api int gn_code_densityx_size(size_t *size, ///< [out] Output array size + int64_t min, ///< [in] Min code + int64_t max ///< [in] Max code +); /** @} CodeDensityHelpers */ @@ -632,86 +613,91 @@ extern "C" { /** * @brief gn_fft_analysis returns all Fourier analysis results * @return 0 on success, non-zero otherwise - * @details The results contain the following key-value pairs (see general description of + * @details The results contain the following key-value pairs (see general + * description of * \ref AnalysisRoutines "Analysis Routines"). * - *
Key Description Units - *
signaltype Signal type: 0=Real, 1=Complex - *
nfft FFT size - *
datasize Data size - *
fbin Frequency bin size Hz - *
fdata Data rate S/s - *
fsample Sample rate S/s - *
fshift Shift frequency Hz - *
fsnr Full-scale-to-noise ratio (a.k.a. "SNRFS") dB - *
snr Signal-to-noise ratio dB - *
sinad Signal-to-noise-and-distortion ratio dB - *
sfdr Spurious-free dynamic range dB - *
abn Average bin noise dBFS - *
nsd Noise spectral density dBFS/Hz - *
carrierindex Order index of the Carrier tone - *
maxspurindex Order index of the MaxSpur tone - *
ab_width Analysis band width Hz - *
ab_i1 Analysis band first index - *
ab_i2 Analysis band last index - *
{PREFIX}_nbins Number of bins associated with PREFIX - *
{PREFIX}_rss Root-sum-square associated with PREFIX - *
{TONEKEY}:orderindex Tone order index - *
{TONEKEY}:freq Tone frequency Hz - *
{TONEKEY}:ffinal Tone final frequency Hz - *
{TONEKEY}:fwavg Tone weighted-average frequency Hz - *
{TONEKEY}:i1 Tone first index - *
{TONEKEY}:i2 Tone last index - *
{TONEKEY}:nbins Tone number of bins - *
{TONEKEY}:inband 0: tone is in-band; 1: tone is out-of-band - *
{TONEKEY}:mag Tone magnitude - *
{TONEKEY}:mag_dbfs Tone magnitude relative to full-scale dBFS - *
{TONEKEY}:mag_dbc Tone magnitude relative to carrier dBc - *
{TONEKEY}:phase Tone phase rad - *
{TONEKEY}:phase_c Tone phase relative to carrier rad + *
Key Description Units
+ * signaltype Signal type: 0=Real, 1=Complex + *
nfft FFT size
datasize + * Data size
fbin + * Frequency bin size Hz
fdata + * Data rate S/s
fsample + * Sample rate S/s
fshift + * Shift frequency Hz
fsnr + * Full-scale-to-noise ratio (a.k.a. "SNRFS") dB
snr + * Signal-to-noise ratio dB
sinad + * Signal-to-noise-and-distortion ratio dB
sfdr + * Spurious-free dynamic range dB
abn + * Average bin noise dBFS
nsd + * Noise spectral density dBFS/Hz
+ * carrierindex Order index of the Carrier tone + *
maxspurindex Order index of the MaxSpur tone + *
ab_width Analysis band width Hz
+ * ab_i1 Analysis band first index + *
ab_i2 Analysis band last index
+ * {PREFIX}_nbins Number of bins associated with PREFIX + *
{PREFIX}_rss Root-sum-square associated with PREFIX + *
{TONEKEY}:orderindex Tone order index
+ * {TONEKEY}:freq Tone frequency + * Hz
{TONEKEY}:ffinal Tone final frequency Hz
+ * {TONEKEY}:fwavg Tone weighted-average frequency + * Hz
{TONEKEY}:i1 Tone first index
+ * {TONEKEY}:i2 Tone last index + *
{TONEKEY}:nbins Tone number of bins
+ * {TONEKEY}:inband 0: tone is in-band; 1: tone is out-of-band + *
{TONEKEY}:mag Tone magnitude
+ * {TONEKEY}:mag_dbfs Tone magnitude relative to full-scale + * dBFS
{TONEKEY}:mag_dbc Tone magnitude relative to carrier + * dBc
{TONEKEY}:phase Tone phase rad
+ * {TONEKEY}:phase_c Tone phase relative to carrier + * rad *
*/ __api int gn_fft_analysis( - char** rkeys, ///< [out] Result keys array pointer - size_t rkeys_size, ///< [in] Result keys array size - double* rvalues, ///< [out] Result values array pointer - size_t rvalues_size, ///< [in] Result values array size - const char* cfg_id, ///< [in] Configuration identifier (filename or object key) - const double* in, ///< [in] Interleaved Re/Im input array pointer - size_t in_size, ///< [in] Input array size - size_t nfft, ///< [in] FFT size - GnFreqAxisType axis_type ///< [in] Frequency axis type - ); + char **rkeys, ///< [out] Result keys array pointer + size_t rkeys_size, ///< [in] Result keys array size + double *rvalues, ///< [out] Result values array pointer + size_t rvalues_size, ///< [in] Result values array size + const char * + cfg_id, ///< [in] Configuration identifier (filename or object key) + const double *in, ///< [in] Interleaved Re/Im input array pointer + size_t in_size, ///< [in] Input array size + size_t nfft, ///< [in] FFT size + GnFreqAxisType axis_type ///< [in] Frequency axis type +); /** * @brief gn_fft_analysis_select returns select Fourier analysis results * @return 0 on success, non-zero otherwise */ __api int gn_fft_analysis_select( - double* rvalues, ///< [out] Result values array pointer - size_t rvalues_size, ///< [in] Result values array size - const char* cfg_id, ///< [in] Configuration identifier (filename or object key) - const char** rkeys, ///< [in] Result keys array pointer - size_t rkeys_size, ///< [in] Result keys array size - const double* in, ///< [in] Interleaved Re/Im input array pointer - size_t in_size, ///< [in] Input array size - size_t nfft, ///< [in] FFT size - GnFreqAxisType axis_type ///< [in] Frequency axis type - ); + double *rvalues, ///< [out] Result values array pointer + size_t rvalues_size, ///< [in] Result values array size + const char * + cfg_id, ///< [in] Configuration identifier (filename or object key) + const char **rkeys, ///< [in] Result keys array pointer + size_t rkeys_size, ///< [in] Result keys array size + const double *in, ///< [in] Interleaved Re/Im input array pointer + size_t in_size, ///< [in] Input array size + size_t nfft, ///< [in] FFT size + GnFreqAxisType axis_type ///< [in] Frequency axis type +); /** * @brief gn_fft_analysis_single returns a single Fourier analysis result * @return 0 on success, non-zero otherwise */ __api int gn_fft_analysis_single( - double* rvalue, ///< [out] Result value - const char* cfg_id, ///< [in] Configuration identifier (filename or object key) - const char* rkey, ///< [in] Result key - const double* in, ///< [in] Interleaved Re/Im input array pointer - size_t in_size, ///< [in] Input array size - size_t nfft, ///< [in] FFT size - GnFreqAxisType axis_type ///< [in] Frequency axis type - ); + double *rvalue, ///< [out] Result value + const char * + cfg_id, ///< [in] Configuration identifier (filename or object key) + const char *rkey, ///< [in] Result key + const double *in, ///< [in] Interleaved Re/Im input array pointer + size_t in_size, ///< [in] Input array size + size_t nfft, ///< [in] FFT size + GnFreqAxisType axis_type ///< [in] Frequency axis type +); /** * \defgroup FourierAnalysisConfiguration Configuration @@ -722,263 +708,245 @@ __api int gn_fft_analysis_single( * @brief gn_fa_analysis_band * @return 0 on success, non-zero otherwise */ -__api int gn_fa_analysis_band( - const char* obj_key, ///< [in] Object key - double center, ///< [in] Analysis band center - double width ///< [in] Analysis band width - ); +__api int gn_fa_analysis_band(const char *obj_key, ///< [in] Object key + double center, ///< [in] Analysis band center + double width ///< [in] Analysis band width +); /** * @brief gn_fa_analysis_band_e * @return 0 on success, non-zero otherwise */ __api int gn_fa_analysis_band_e( - const char* obj_key, ///< [in] Object key - const char* center, ///< [in] Analysis band center expression - const char* width ///< [in] Analysis band width expression - ); + const char *obj_key, ///< [in] Object key + const char *center, ///< [in] Analysis band center expression + const char *width ///< [in] Analysis band width expression +); /** * @brief gn_fa_clk * @return 0 on success, non-zero otherwise */ __api int gn_fa_clk( - const char* obj_key, ///< [in] Object key - const int* clk, ///< [in] Pointer to array of clock divisors - size_t clk_size, ///< [in] Size of array of clock divisors - bool as_noise ///< [in] If true, CLK components will be treated as noise - ); + const char *obj_key, ///< [in] Object key + const int *clk, ///< [in] Pointer to array of clock divisors + size_t clk_size, ///< [in] Size of array of clock divisors + bool as_noise ///< [in] If true, CLK components will be treated as noise +); /** * @brief gn_fa_conv_offset * @return 0 on success, non-zero otherwise */ -__api int gn_fa_conv_offset( - const char* obj_key, ///< [in] Object key - bool enable ///< [in] If true, enable converter offset - ); +__api int +gn_fa_conv_offset(const char *obj_key, ///< [in] Object key + bool enable ///< [in] If true, enable converter offset +); /** * @brief gn_fa_create * @return 0 on success, non-zero otherwise */ -__api int gn_fa_create( - const char* obj_key ///< [in] Object key - ); +__api int gn_fa_create(const char *obj_key ///< [in] Object key +); /** * @brief gn_fa_dc * @return 0 on success, non-zero otherwise */ -__api int gn_fa_dc( - const char* obj_key, ///< [in] Object key - bool as_dist ///< [in] If true, treat DC as distortion - ); +__api int gn_fa_dc(const char *obj_key, ///< [in] Object key + bool as_dist ///< [in] If true, treat DC as distortion +); /** * @brief gn_fa_fdata * @return 0 on success, non-zero otherwise */ -__api int gn_fa_fdata( - const char* obj_key, ///< [in] Object key - double f ///< [in] fdata - ); +__api int gn_fa_fdata(const char *obj_key, ///< [in] Object key + double f ///< [in] fdata +); /** * @brief gn_fa_fdata_e * @return 0 on success, non-zero otherwise */ -__api int gn_fa_fdata_e( - const char* obj_key, ///< [in] Object key - const char* f ///< [in] fdata expression - ); +__api int gn_fa_fdata_e(const char *obj_key, ///< [in] Object key + const char *f ///< [in] fdata expression +); /** * @brief gn_fa_fixed_tone * @return 0 on success, non-zero otherwise */ -__api int gn_fa_fixed_tone( - const char* obj_key, ///< [in] Object key - const char* comp_key, ///< [in] Component key - GnFACompTag tag, ///< [in] Tag - double freq, ///< [in] Frequency - int ssb ///< [in] Number of single-side bins - ); +__api int gn_fa_fixed_tone(const char *obj_key, ///< [in] Object key + const char *comp_key, ///< [in] Component key + GnFACompTag tag, ///< [in] Tag + double freq, ///< [in] Frequency + int ssb ///< [in] Number of single-side bins +); /** * @brief gn_fa_fixed_tone_e * @return 0 on success, non-zero otherwise */ -__api int gn_fa_fixed_tone_e( - const char* obj_key, ///< [in] Object key - const char* comp_key, ///< [in] Component key - GnFACompTag tag, ///< [in] Tag - const char* freq, ///< [in] Frequency expression - int ssb ///< [in] Number of single-side bins - ); +__api int gn_fa_fixed_tone_e(const char *obj_key, ///< [in] Object key + const char *comp_key, ///< [in] Component key + GnFACompTag tag, ///< [in] Tag + const char *freq, ///< [in] Frequency expression + int ssb ///< [in] Number of single-side bins +); /** * @brief gn_fa_fsample * @return 0 on success, non-zero otherwise */ -__api int gn_fa_fsample( - const char* obj_key, ///< [in] Object key - double f ///< [in] fsample - ); +__api int gn_fa_fsample(const char *obj_key, ///< [in] Object key + double f ///< [in] fsample +); /** * @brief gn_fa_fsample_e * @return 0 on success, non-zero otherwise */ -__api int gn_fa_fsample_e( - const char* obj_key, ///< [in] Object key - const char* f ///< [in] fsample expression - ); +__api int gn_fa_fsample_e(const char *obj_key, ///< [in] Object key + const char *f ///< [in] fsample expression +); /** * @brief gn_fa_fshift * @return 0 on success, non-zero otherwise */ -__api int gn_fa_fshift( - const char* obj_key, ///< [in] Object key - double f ///< [in] fshift - ); +__api int gn_fa_fshift(const char *obj_key, ///< [in] Object key + double f ///< [in] fshift +); /** * @brief gn_fa_fshift_e * @return 0 on success, non-zero otherwise */ -__api int gn_fa_fshift_e( - const char* obj_key, ///< [in] Object key - const char* f ///< [in] fshift expression - ); +__api int gn_fa_fshift_e(const char *obj_key, ///< [in] Object key + const char *f ///< [in] fshift expression +); /** * @brief gn_fa_fund_images * @return 0 on success, non-zero otherwise */ -__api int gn_fa_fund_images( - const char* obj_key, ///< [in] Object key - bool enable ///< [in] If true, enable fundamental images - ); +__api int +gn_fa_fund_images(const char *obj_key, ///< [in] Object key + bool enable ///< [in] If true, enable fundamental images +); /** * @brief gn_fa_hd * @return 0 on success, non-zero otherwise */ __api int gn_fa_hd( - const char* obj_key, ///< [in] Object key - int n ///< [in] Order of harmonic distortion, i.e., the maximum harmonic - ); + const char *obj_key, ///< [in] Object key + int n ///< [in] Order of harmonic distortion, i.e., the maximum harmonic +); /** * @brief gn_fa_ilv * @return 0 on success, non-zero otherwise */ __api int gn_fa_ilv( - const char* obj_key, ///< [in] Object key - const int* ilv, ///< [in] Pointer to array of interleaving factors - size_t ilv_size, ///< [in] Size of array of interleaving factors - bool as_noise ///< [in] If true, ILV components will be treated as noise - ); + const char *obj_key, ///< [in] Object key + const int *ilv, ///< [in] Pointer to array of interleaving factors + size_t ilv_size, ///< [in] Size of array of interleaving factors + bool as_noise ///< [in] If true, ILV components will be treated as noise +); /** * @brief gn_fa_imd * @return 0 on success, non-zero otherwise */ -__api int gn_fa_imd( - const char* obj_key, ///< [in] Object key - int n ///< [in] Order of intermodulation distortion - ); +__api int gn_fa_imd(const char *obj_key, ///< [in] Object key + int n ///< [in] Order of intermodulation distortion +); /** * @brief gn_fa_load * @return 0 on success, non-zero otherwise * @details If obj_key is empty, the object key is derived from filename. */ -__api int gn_fa_load( - char* buf, ///< [out] Pointer to character array - size_t size, ///< [in] Size of character array - const char* filename, ///< [in] Filename - const char* obj_key ///< [in] Object key - ); +__api int gn_fa_load(char *buf, ///< [out] Pointer to character array + size_t size, ///< [in] Size of character array + const char *filename, ///< [in] Filename + const char *obj_key ///< [in] Object key +); /** * @brief gn_fa_max_tone * @return 0 on success, non-zero otherwise */ -__api int gn_fa_max_tone( - const char* obj_key, ///< [in] Object key - const char* comp_key, ///< [in] Component key - GnFACompTag tag, ///< [in] Tag - int ssb ///< [in] Number of single-side bins - ); +__api int gn_fa_max_tone(const char *obj_key, ///< [in] Object key + const char *comp_key, ///< [in] Component key + GnFACompTag tag, ///< [in] Tag + int ssb ///< [in] Number of single-side bins +); /** * @brief gn_fa_preview * @return 0 on success, non-zero otherwise */ __api int gn_fa_preview( - char* buf, ///< [out] Pointer to character array - size_t size, ///< [in] Size of character array - const char* cfg_id, ///< [in] Configuration identifier (filename or object key) - bool cplx ///< [in] If true, preview will include complex components - ); + char *buf, ///< [out] Pointer to character array + size_t size, ///< [in] Size of character array + const char * + cfg_id, ///< [in] Configuration identifier (filename or object key) + bool cplx ///< [in] If true, preview will include complex components +); /** * @brief gn_fa_quad_errors * @return 0 on success, non-zero otherwise */ -__api int gn_fa_quad_errors( - const char* obj_key, ///< [in] Object key - bool enable ///< [in] If true, enable quadrature errors - ); +__api int +gn_fa_quad_errors(const char *obj_key, ///< [in] Object key + bool enable ///< [in] If true, enable quadrature errors +); /** * @brief gn_fa_remove_comp * @return 0 on success, non-zero otherwise */ -__api int gn_fa_remove_comp( - const char* obj_key, ///< [in] Object key - const char* comp_key ///< [in] Component key - ); +__api int gn_fa_remove_comp(const char *obj_key, ///< [in] Object key + const char *comp_key ///< [in] Component key +); /** * @brief gn_fa_reset * @return 0 on success, non-zero otherwise */ -__api int gn_fa_reset( - const char* obj_key ///< [in] Object key - ); +__api int gn_fa_reset(const char *obj_key ///< [in] Object key +); /** * @brief gn_fa_ssb * @return 0 on success, non-zero otherwise */ -__api int gn_fa_ssb( - const char* obj_key, ///< [in] Object key - GnFASsb group, ///< [in] SSB group - int ssb ///< [in] Number of single-side bins - ); +__api int gn_fa_ssb(const char *obj_key, ///< [in] Object key + GnFASsb group, ///< [in] SSB group + int ssb ///< [in] Number of single-side bins +); /** * @brief gn_fa_var * @return 0 on success, non-zero otherwise */ -__api int gn_fa_var( - const char* obj_key, ///< [in] Object key - const char* name, ///< [in] Variable name - double value ///< [in] Variable value - ); +__api int gn_fa_var(const char *obj_key, ///< [in] Object key + const char *name, ///< [in] Variable name + double value ///< [in] Variable value +); /** * @brief gn_fa_wo * @return 0 on success, non-zero otherwise */ -__api int gn_fa_wo( - const char* obj_key, ///< [in] Object key - int n ///< [in] Number of worst others - ); +__api int gn_fa_wo(const char *obj_key, ///< [in] Object key + int n ///< [in] Number of worst others +); /** @} FourierAnalysisConfiguration */ @@ -991,27 +959,27 @@ __api int gn_fa_wo( * @brief gn_fa_result * @return 0 on success, non-zero otherwise */ -__api int gn_fa_result( - double* result, ///< [out] Result associated with rkey - const char** rkeys, ///< [in] Result keys array pointer - size_t rkeys_size, ///< [in] Result keys array size - const double* rvalues, ///< [in] Result values array pointer - size_t rvalues_size, ///< [in] Result values array size - const char* rkey ///< [in] Key of desired result +__api int +gn_fa_result(double *result, ///< [out] Result associated with rkey + const char **rkeys, ///< [in] Result keys array pointer + size_t rkeys_size, ///< [in] Result keys array size + const double *rvalues, ///< [in] Result values array pointer + size_t rvalues_size, ///< [in] Result values array size + const char *rkey ///< [in] Key of desired result ); /** * @brief gn_fa_result_string * @return 0 on success, non-zero otherwise */ -__api int gn_fa_result_string( - char* result, ///< [out] Result string associated with rkey - size_t result_size, ///< [in] Size of result string - const char** rkeys, ///< [in] Result keys array pointer - size_t rkeys_size, ///< [in] Result keys array size - const double* rvalues, ///< [in] Result values array pointer - size_t rvalues_size, ///< [in] Result values array size - const char* rkey ///< [in] Key of desired result +__api int +gn_fa_result_string(char *result, ///< [out] Result string associated with rkey + size_t result_size, ///< [in] Size of result string + const char **rkeys, ///< [in] Result keys array pointer + size_t rkeys_size, ///< [in] Result keys array size + const double *rvalues, ///< [in] Result values array pointer + size_t rvalues_size, ///< [in] Result values array size + const char *rkey ///< [in] Key of desired result ); /** @} FourierAnalysisResults */ @@ -1024,66 +992,70 @@ __api int gn_fa_result_string( /** * @brief gn_fa_load_key_size * @return 0 on success, non-zero otherwise - * @details The library string termination setting determines whether or not a null terminator - * is included in the size. See \ref gn_set_string_termination. + * @details The library string termination setting determines whether or not a + * null terminator is included in the size. See \ref gn_set_string_termination. */ -__api int gn_fa_load_key_size( - size_t* size, ///< [out] Number of characters in key - const char* filename, ///< [in] Filename - const char* obj_key ///< [in] Object key - ); +__api int +gn_fa_load_key_size(size_t *size, ///< [out] Number of characters in key + const char *filename, ///< [in] Filename + const char *obj_key ///< [in] Object key +); /** * @brief gn_fa_preview_size * @return 0 on success, non-zero otherwise - * @details The library string termination setting determines whether or not a null terminator - * is included in the size. See \ref gn_set_string_termination. + * @details The library string termination setting determines whether or not a + * null terminator is included in the size. See \ref gn_set_string_termination. */ __api int gn_fa_preview_size( - size_t* size, ///< [out] Number of characters in compenent list string - const char* cfg_id, ///< [in] Configuration identifier (filename or object key) - bool cplx ///< [in] If true, list will include complex components - ); + size_t *size, ///< [out] Number of characters in compenent list string + const char * + cfg_id, ///< [in] Configuration identifier (filename or object key) + bool cplx ///< [in] If true, list will include complex components +); /** * @brief gn_fa_result_string_size * @return 0 on success, non-zero otherwise - * @details The library string termination setting determines whether or not a null terminator - * is included in the size. See \ref gn_set_string_termination. + * @details The library string termination setting determines whether or not a + * null terminator is included in the size. See \ref gn_set_string_termination. */ __api int gn_fa_result_string_size( - size_t* size, ///< [out] Number of characters result string - const char** rkeys, ///< [in] Result keys array pointer - size_t rkeys_size, ///< [in] Result keys array size - const double* rvalues, ///< [in] Result values array pointer - size_t rvalues_size, ///< [in] Result values array size - const char* rkey ///< [in] Key of desired result - ); + size_t *size, ///< [out] Number of characters result string + const char **rkeys, ///< [in] Result keys array pointer + size_t rkeys_size, ///< [in] Result keys array size + const double *rvalues, ///< [in] Result values array pointer + size_t rvalues_size, ///< [in] Result values array size + const char *rkey ///< [in] Key of desired result +); /** * @brief gn_fft_analysis_results_key_sizes * @return 0 on success, non-zero otherwise - * @details The library string termination setting determines whether or not a null terminator - * is included in the key sizes. See \ref gn_set_string_termination. + * @details The library string termination setting determines whether or not a + * null terminator is included in the key sizes. See \ref + * gn_set_string_termination. */ __api int gn_fft_analysis_results_key_sizes( - size_t* key_sizes, ///< [out] Key size array pointer - size_t key_sizes_size, ///< [in] Key size array size - const char* cfg_id, ///< [in] Configuration identifier (filename or object key) - size_t in_size, ///< [in] Input array size - size_t nfft ///< [in] FFT size - ); + size_t *key_sizes, ///< [out] Key size array pointer + size_t key_sizes_size, ///< [in] Key size array size + const char * + cfg_id, ///< [in] Configuration identifier (filename or object key) + size_t in_size, ///< [in] Input array size + size_t nfft ///< [in] FFT size +); /** * @brief gn_fft_analysis_results_size * @return 0 on success, non-zero otherwise */ __api int gn_fft_analysis_results_size( - size_t* size, ///< [out] Number of key-value result pairs - const char* cfg_id, ///< [in] Configuration identifier (filename or object key) - size_t in_size, ///< [in] Input array size - size_t nfft ///< [in] FFT size - ); + size_t *size, ///< [out] Number of key-value result pairs + const char * + cfg_id, ///< [in] Configuration identifier (filename or object key) + size_t in_size, ///< [in] Input array size + size_t nfft ///< [in] FFT size +); /** @} FourierAnalysisHelpers */ @@ -1103,142 +1075,140 @@ extern "C" { * @{ */ - /** +/** * @brief gn_fft * @return 0 on success, non-zero otherwise */ -__api int gn_fft( - double* out, ///< [out] Interleaved Re/Im output array pointer - size_t out_size, ///< [in] Output array size - const double* i, ///< [in] In-phase input array pointer - size_t i_size, ///< [in] In-phase input array size - const double* q, ///< [in] Quadrature input array pointer - size_t q_size, ///< [in] Quadrature input array size - size_t navg, ///< [in] FFT averaging number - size_t nfft, ///< [in] FFT size - GnWindow window ///< [in] Window - ); +__api int gn_fft(double *out, ///< [out] Interleaved Re/Im output array pointer + size_t out_size, ///< [in] Output array size + const double *i, ///< [in] In-phase input array pointer + size_t i_size, ///< [in] In-phase input array size + const double *q, ///< [in] Quadrature input array pointer + size_t q_size, ///< [in] Quadrature input array size + size_t navg, ///< [in] FFT averaging number + size_t nfft, ///< [in] FFT size + GnWindow window ///< [in] Window +); /** * @brief gn_fft16 * @return 0 on success, non-zero otherwise */ -__api int gn_fft16( - double* out, ///< [out] Interleaved Re/Im output array pointer - size_t out_size, ///< [in] Output array size - const int16_t* i, ///< [in] In-phase input array pointer - size_t i_size, ///< [in] In-phase input array size - const int16_t* q, ///< [in] Quadrature input array pointer - size_t q_size, ///< [in] Quadrature input array size - int n, ///< [in] Resolution - size_t navg, ///< [in] FFT averaging number - size_t nfft, ///< [in] FFT size - GnWindow window, ///< [in] Window - GnCodeFormat format ///< [in] Code format - ); +__api int +gn_fft16(double *out, ///< [out] Interleaved Re/Im output array pointer + size_t out_size, ///< [in] Output array size + const int16_t *i, ///< [in] In-phase input array pointer + size_t i_size, ///< [in] In-phase input array size + const int16_t *q, ///< [in] Quadrature input array pointer + size_t q_size, ///< [in] Quadrature input array size + int n, ///< [in] Resolution + size_t navg, ///< [in] FFT averaging number + size_t nfft, ///< [in] FFT size + GnWindow window, ///< [in] Window + GnCodeFormat format ///< [in] Code format +); /** * @brief gn_fft32 * @return 0 on success, non-zero otherwise */ -__api int gn_fft32( - double* out, ///< [out] Interleaved Re/Im output array pointer - size_t out_size, ///< [in] Output array size - const int32_t* i, ///< [in] In-phase input array pointer - size_t i_size, ///< [in] In-phase input array size - const int32_t* q, ///< [in] Quadrature input array pointer - size_t q_size, ///< [in] Quadrature input array size - int n, ///< [in] Resolution - size_t navg, ///< [in] FFT averaging number - size_t nfft, ///< [in] FFT size - GnWindow window, ///< [in] Window - GnCodeFormat format ///< [in] Code format - ); +__api int +gn_fft32(double *out, ///< [out] Interleaved Re/Im output array pointer + size_t out_size, ///< [in] Output array size + const int32_t *i, ///< [in] In-phase input array pointer + size_t i_size, ///< [in] In-phase input array size + const int32_t *q, ///< [in] Quadrature input array pointer + size_t q_size, ///< [in] Quadrature input array size + int n, ///< [in] Resolution + size_t navg, ///< [in] FFT averaging number + size_t nfft, ///< [in] FFT size + GnWindow window, ///< [in] Window + GnCodeFormat format ///< [in] Code format +); /** * @brief gn_fft64 * @return 0 on success, non-zero otherwise */ -__api int gn_fft64( - double* out, ///< [out] Interleaved Re/Im output array pointer - size_t out_size, ///< [in] Output array size - const int64_t* i, ///< [in] In-phase input array pointer - size_t i_size, ///< [in] In-phase input array size - const int64_t* q, ///< [in] Quadrature input array pointer - size_t q_size, ///< [in] Quadrature input array size - int n, ///< [in] Resolution - size_t navg, ///< [in] FFT averaging number - size_t nfft, ///< [in] FFT size - GnWindow window, ///< [in] Window - GnCodeFormat format ///< [in] Code format - ); +__api int +gn_fft64(double *out, ///< [out] Interleaved Re/Im output array pointer + size_t out_size, ///< [in] Output array size + const int64_t *i, ///< [in] In-phase input array pointer + size_t i_size, ///< [in] In-phase input array size + const int64_t *q, ///< [in] Quadrature input array pointer + size_t q_size, ///< [in] Quadrature input array size + int n, ///< [in] Resolution + size_t navg, ///< [in] FFT averaging number + size_t nfft, ///< [in] FFT size + GnWindow window, ///< [in] Window + GnCodeFormat format ///< [in] Code format +); /** * @brief gn_rfft * @return 0 on success, non-zero otherwise * @details This function will be implemented in the future. */ -__api int gn_rfft( - double* out, ///< [out] Interleaved Re/Im output array pointer - size_t out_size, ///< [in] Output array size - const double* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - size_t navg, ///< [in] FFT averaging number - size_t nfft, ///< [in] FFT size - GnWindow window, ///< [in] Window - GnRfftScale scale ///< [in] Scaling mode - ); +__api int gn_rfft(double *out, ///< [out] Interleaved Re/Im output array pointer + size_t out_size, ///< [in] Output array size + const double *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + size_t navg, ///< [in] FFT averaging number + size_t nfft, ///< [in] FFT size + GnWindow window, ///< [in] Window + GnRfftScale scale ///< [in] Scaling mode +); /** * @brief gn_rfft16 * @return 0 on success, non-zero otherwise */ -__api int gn_rfft16( - double* out, ///< [out] Interleaved Re/Im output array pointer - size_t out_size, ///< [in] Output array size - const int16_t* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - int n, ///< [in] Resolution - size_t navg, ///< [in] FFT averaging number - size_t nfft, ///< [in] FFT size - GnWindow window, ///< [in] Window - GnCodeFormat format, ///< [in] Code format - GnRfftScale scale ///< [in] Scaling mode - ); +__api int +gn_rfft16(double *out, ///< [out] Interleaved Re/Im output array pointer + size_t out_size, ///< [in] Output array size + const int16_t *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + int n, ///< [in] Resolution + size_t navg, ///< [in] FFT averaging number + size_t nfft, ///< [in] FFT size + GnWindow window, ///< [in] Window + GnCodeFormat format, ///< [in] Code format + GnRfftScale scale ///< [in] Scaling mode +); /** * @brief gn_rfft32 * @return 0 on success, non-zero otherwise */ -__api int gn_rfft32( - double* out, ///< [out] Interleaved Re/Im output array pointer - size_t out_size, ///< [in] Output array size - const int32_t* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - int n, ///< [in] Resolution - size_t navg, ///< [in] FFT averaging number - size_t nfft, ///< [in] FFT size - GnWindow window, ///< [in] Window - GnCodeFormat format, ///< [in] Code format - GnRfftScale scale ///< [in] Scaling mode - ); +__api int +gn_rfft32(double *out, ///< [out] Interleaved Re/Im output array pointer + size_t out_size, ///< [in] Output array size + const int32_t *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + int n, ///< [in] Resolution + size_t navg, ///< [in] FFT averaging number + size_t nfft, ///< [in] FFT size + GnWindow window, ///< [in] Window + GnCodeFormat format, ///< [in] Code format + GnRfftScale scale ///< [in] Scaling mode +); /** * @brief gn_rfft64 * @return 0 on success, non-zero otherwise */ -__api int gn_rfft64( - double* out, ///< [out] Interleaved Re/Im output array pointer - size_t out_size, ///< [in] Output array size - const int64_t* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - int n, ///< [in] Resolution - size_t navg, ///< [in] FFT averaging number - size_t nfft, ///< [in] FFT size - GnWindow window, ///< [in] Window - GnCodeFormat format, ///< [in] Code format - GnRfftScale scale ///< [in] Scaling mode - ); +__api int +gn_rfft64(double *out, ///< [out] Interleaved Re/Im output array pointer + size_t out_size, ///< [in] Output array size + const int64_t *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + int n, ///< [in] Resolution + size_t navg, ///< [in] FFT averaging number + size_t nfft, ///< [in] FFT size + GnWindow window, ///< [in] Window + GnCodeFormat format, ///< [in] Code format + GnRfftScale scale ///< [in] Scaling mode +); /** * \defgroup FourierTransformHelpers Helpers @@ -1249,24 +1219,22 @@ __api int gn_rfft64( * @brief gn_fft_size * @return 0 on success, non-zero otherwise */ -__api int gn_fft_size( - size_t* out_size, ///< [out] Output array size - size_t i_size, ///< [in] In-phase input array size - size_t q_size, ///< [in] Quadrature input array size - size_t navg, ///< [in] FFT averaging number - size_t nfft ///< [in] FFT size - ); +__api int gn_fft_size(size_t *out_size, ///< [out] Output array size + size_t i_size, ///< [in] In-phase input array size + size_t q_size, ///< [in] Quadrature input array size + size_t navg, ///< [in] FFT averaging number + size_t nfft ///< [in] FFT size +); /** * @brief gn_rfft_size * @return 0 on success, non-zero otherwise */ -__api int gn_rfft_size( - size_t* out_size, ///< [out] Output array size - size_t in_size, ///< [in] Input array size - size_t navg, ///< [in] FFT averaging number - size_t nfft ///< [in] FFT size - ); +__api int gn_rfft_size(size_t *out_size, ///< [out] Output array size + size_t in_size, ///< [in] Input array size + size_t navg, ///< [in] FFT averaging number + size_t nfft ///< [in] FFT size +); /** @} FourierTransformHelpers */ @@ -1290,58 +1258,54 @@ extern "C" { * @brief gn_alias * @return 0 on success, non-zero otherwise */ -__api int gn_alias( - double* out, ///< [out] Output pointer - double fs, ///< [in] Sample rate (S/s) - double freq, ///< [in] Frequency (Hz) - GnFreqAxisType axis_type ///< [in] Frequency axis type - ); +__api int gn_alias(double *out, ///< [out] Output pointer + double fs, ///< [in] Sample rate (S/s) + double freq, ///< [in] Frequency (Hz) + GnFreqAxisType axis_type ///< [in] Frequency axis type +); /** * @brief gn_coherent * @return 0 on success, non-zero otherwise */ -__api int gn_coherent( - double* out, ///< [out] Output pointer - size_t nfft, ///< [in] FFT size - double fs, ///< [in] Sample rate (S/s) - double freq ///< [in] Desired frequency (Hz) - ); +__api int gn_coherent(double *out, ///< [out] Output pointer + size_t nfft, ///< [in] FFT size + double fs, ///< [in] Sample rate (S/s) + double freq ///< [in] Desired frequency (Hz) +); /** * @brief gn_fftshift * @return 0 on success, non-zero otherwise */ -__api int gn_fftshift( - double* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const double* in, ///< [in] Input array pointer - size_t in_size ///< [in] Input array size - ); +__api int gn_fftshift(double *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const double *in, ///< [in] Input array pointer + size_t in_size ///< [in] Input array size +); /** * @brief gn_freq_axis * @return 0 on success, non-zero otherwise */ -__api int gn_freq_axis( - double* out, ///< [out] Array pointer - size_t size, ///< [in] Array size - size_t nfft, ///< [in] FFT size - GnFreqAxisType axis_type, ///< [in] Frequency axis type - double fs, ///< [in] Sample rate (S/s) - GnFreqAxisFormat axis_format ///< [in] Frequency axis format - ); +__api int +gn_freq_axis(double *out, ///< [out] Array pointer + size_t size, ///< [in] Array size + size_t nfft, ///< [in] FFT size + GnFreqAxisType axis_type, ///< [in] Frequency axis type + double fs, ///< [in] Sample rate (S/s) + GnFreqAxisFormat axis_format ///< [in] Frequency axis format +); /** * @brief gn_ifftshift * @return 0 on success, non-zero otherwise */ -__api int gn_ifftshift( - double* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const double* in, ///< [in] Input array pointer - size_t in_size ///< [in] Input array size - ); +__api int gn_ifftshift(double *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const double *in, ///< [in] Input array pointer + size_t in_size ///< [in] Input array size +); /** * \defgroup FourierUtilityHelpers Helpers @@ -1352,11 +1316,11 @@ __api int gn_ifftshift( * @brief gn_freq_axis_size * @return 0 on success, non-zero otherwise */ -__api int gn_freq_axis_size( - size_t* size, ///< [out] Output array size - size_t nfft, ///< [in] FFT size - GnFreqAxisType axis_type ///< [in] Frequency axis type - ); +__api int +gn_freq_axis_size(size_t *size, ///< [out] Output array size + size_t nfft, ///< [in] FFT size + GnFreqAxisType axis_type ///< [in] Frequency axis type +); /** @} FourierUtilityHelpers */ @@ -1387,67 +1351,63 @@ __api int gn_mgr_clear(); * @return 0 on success, non-zero otherwise */ __api int gn_mgr_compare( - bool* result, ///< [out] true if the objects are equal, false otherwise - const char* obj_key1, ///< [in] Object key 1 - const char* obj_key2 ///< [in] Object key 2 - ); + bool *result, ///< [out] true if the objects are equal, false otherwise + const char *obj_key1, ///< [in] Object key 1 + const char *obj_key2 ///< [in] Object key 2 +); /** * @brief gn_mgr_contains * @return Always returns 0 */ __api int gn_mgr_contains( - bool* result, ///< [out] true if Manager contains key, false otherwise - const char* obj_key ///< [in] Object key - ); + bool *result, ///< [out] true if Manager contains key, false otherwise + const char *obj_key ///< [in] Object key +); /** * @brief gn_mgr_remove * @return Always returns 0 */ -__api int gn_mgr_remove( - const char* obj_key ///< [in] Object key - ); +__api int gn_mgr_remove(const char *obj_key ///< [in] Object key +); /** * @brief gn_mgr_save * @return 0 on success, non-zero otherwise * @details If filename is empty, the filename is derived from obj_key. */ -__api int gn_mgr_save( - char* buf, ///< [out] Pointer to character array - size_t size, ///< [in] Size of character array - const char* obj_key, ///< [in] Object key - const char* filename ///< [in] Filename - ); +__api int gn_mgr_save(char *buf, ///< [out] Pointer to character array + size_t size, ///< [in] Size of character array + const char *obj_key, ///< [in] Object key + const char *filename ///< [in] Filename +); /** * @brief gn_mgr_size * @return Always returns 0 */ -__api int gn_mgr_size( - size_t* size ///< [out] Number of objects owned by the manager - ); +__api int +gn_mgr_size(size_t *size ///< [out] Number of objects owned by the manager +); /** * @brief gn_mgr_to_string * @return 0 on success, non-zero otherwise */ -__api int gn_mgr_to_string( - char* buf, ///< [out] Pointer to character array - size_t size, ///< [in] Size of character array - const char* obj_key ///< [in] Object key - ); +__api int gn_mgr_to_string(char *buf, ///< [out] Pointer to character array + size_t size, ///< [in] Size of character array + const char *obj_key ///< [in] Object key +); /** * @brief gn_mgr_type * @return 0 on success, non-zero otherwise */ -__api int gn_mgr_type( - char* buf, ///< [out] Pointer to character array - size_t size, ///< [in] Size of character array - const char* obj_key ///< [in] Object key - ); +__api int gn_mgr_type(char *buf, ///< [out] Pointer to character array + size_t size, ///< [in] Size of character array + const char *obj_key ///< [in] Object key +); /** * \defgroup ManagerHelpers Helpers @@ -1457,36 +1417,36 @@ __api int gn_mgr_type( /** * @brief gn_mgr_save_filename_size * @return 0 on success, non-zero otherwise - * @details The library string termination setting determines whether or not a null terminator - * is included in the size. See \ref gn_set_string_termination. + * @details The library string termination setting determines whether or not a + * null terminator is included in the size. See \ref gn_set_string_termination. */ __api int gn_mgr_save_filename_size( - size_t* size, ///< [out] Number of characters in filename - const char* obj_key, ///< [in] Object key - const char* filename ///< [in] Filename - ); + size_t *size, ///< [out] Number of characters in filename + const char *obj_key, ///< [in] Object key + const char *filename ///< [in] Filename +); /** * @brief gn_mgr_to_string_size * @return 0 on success, non-zero otherwise - * @details The library string termination setting determines whether or not a null terminator - * is included in the size. See \ref gn_set_string_termination. + * @details The library string termination setting determines whether or not a + * null terminator is included in the size. See \ref gn_set_string_termination. */ __api int gn_mgr_to_string_size( - size_t* size, ///< [out] Number of characters in the string - const char* obj_key ///< [in] Object key - ); + size_t *size, ///< [out] Number of characters in the string + const char *obj_key ///< [in] Object key +); /** * @brief gn_mgr_type_size * @return 0 on success, non-zero otherwise - * @details The library string termination setting determines whether or not a null terminator - * is included in the size. See \ref gn_set_string_termination. + * @details The library string termination setting determines whether or not a + * null terminator is included in the size. See \ref gn_set_string_termination. */ __api int gn_mgr_type_size( - size_t* size, ///< [out] Number of characters in object type string - const char* obj_key ///< [in] Object key - ); + size_t *size, ///< [out] Number of characters in object type string + const char *obj_key ///< [in] Object key +); /** @} ManagerHelpers */ @@ -1510,215 +1470,204 @@ extern "C" { * @brief gn_downsample * @return 0 on success, non-zero otherwise */ -__api int gn_downsample( - double* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const double* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - int ratio, ///< [in] Downsample ratio - bool interleaved ///< [in] If true, 'in' is interleaved I/Q data - ); +__api int +gn_downsample(double *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const double *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + int ratio, ///< [in] Downsample ratio + bool interleaved ///< [in] If true, 'in' is interleaved I/Q data +); /** * @brief gn_downsample16 * @return 0 on success, non-zero otherwise */ -__api int gn_downsample16( - int16_t* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const int16_t* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - int ratio, ///< [in] Downsample ratio - bool interleaved ///< [in] If true, 'in' is interleaved I/Q data - ); +__api int +gn_downsample16(int16_t *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const int16_t *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + int ratio, ///< [in] Downsample ratio + bool interleaved ///< [in] If true, 'in' is interleaved I/Q data +); /** * @brief gn_downsample32 * @return 0 on success, non-zero otherwise */ -__api int gn_downsample32( - int32_t* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const int32_t* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - int ratio, ///< [in] Downsample ratio - bool interleaved ///< [in] If true, 'in' is interleaved I/Q data - ); +__api int +gn_downsample32(int32_t *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const int32_t *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + int ratio, ///< [in] Downsample ratio + bool interleaved ///< [in] If true, 'in' is interleaved I/Q data +); /** * @brief gn_downsample64 * @return 0 on success, non-zero otherwise */ -__api int gn_downsample64( - int64_t* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const int64_t* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - int ratio, ///< [in] Downsample ratio - bool interleaved ///< [in] If true, 'in' is interleaved I/Q data - ); +__api int +gn_downsample64(int64_t *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const int64_t *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + int ratio, ///< [in] Downsample ratio + bool interleaved ///< [in] If true, 'in' is interleaved I/Q data +); /** * @brief gn_fshift * @return 0 on success, non-zero otherwise */ -__api int gn_fshift( - double* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const double* i, ///< [in] In-phase input array pointer - size_t i_size, ///< [in] In-phase input array size - const double* q, ///< [in] Quadrature input array pointer - size_t q_size, ///< [in] Quadrature input array size - double fs, ///< [in] Sample rate - double fshift ///< [in] Shift frequency - ); +__api int gn_fshift(double *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const double *i, ///< [in] In-phase input array pointer + size_t i_size, ///< [in] In-phase input array size + const double *q, ///< [in] Quadrature input array pointer + size_t q_size, ///< [in] Quadrature input array size + double fs, ///< [in] Sample rate + double fshift ///< [in] Shift frequency +); /** * @brief gn_fshift16 * @return 0 on success, non-zero otherwise */ -__api int gn_fshift16( - int16_t* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const int16_t* i, ///< [in] In-phase input array pointer - size_t i_size, ///< [in] In-phase input array size - const int16_t* q, ///< [in] Quadrature input array pointer - size_t q_size, ///< [in] Quadrature input array size - int n, ///< [in] Code width - double fs, ///< [in] Sample rate - double fshift, ///< [in] Shift frequency - GnCodeFormat format ///< [in] Code format - ); +__api int gn_fshift16(int16_t *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const int16_t *i, ///< [in] In-phase input array pointer + size_t i_size, ///< [in] In-phase input array size + const int16_t *q, ///< [in] Quadrature input array pointer + size_t q_size, ///< [in] Quadrature input array size + int n, ///< [in] Code width + double fs, ///< [in] Sample rate + double fshift, ///< [in] Shift frequency + GnCodeFormat format ///< [in] Code format +); /** * @brief gn_fshift32 * @return 0 on success, non-zero otherwise */ -__api int gn_fshift32( - int32_t* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const int32_t* i, ///< [in] In-phase input array pointer - size_t i_size, ///< [in] In-phase input array size - const int32_t* q, ///< [in] Quadrature input array pointer - size_t q_size, ///< [in] Quadrature input array size - int n, ///< [in] Code width - double fs, ///< [in] Sample rate - double fshift, ///< [in] Shift frequency - GnCodeFormat format ///< [in] Code format - ); +__api int gn_fshift32(int32_t *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const int32_t *i, ///< [in] In-phase input array pointer + size_t i_size, ///< [in] In-phase input array size + const int32_t *q, ///< [in] Quadrature input array pointer + size_t q_size, ///< [in] Quadrature input array size + int n, ///< [in] Code width + double fs, ///< [in] Sample rate + double fshift, ///< [in] Shift frequency + GnCodeFormat format ///< [in] Code format +); /** * @brief gn_fshift64 * @return 0 on success, non-zero otherwise */ -__api int gn_fshift64( - int64_t* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const int64_t* i, ///< [in] In-phase input array pointer - size_t i_size, ///< [in] In-phase input array size - const int64_t* q, ///< [in] Quadrature input array pointer - size_t q_size, ///< [in] Quadrature input array size - int n, ///< [in] Code width - double fs, ///< [in] Sample rate - double fshift, ///< [in] Shift frequency - GnCodeFormat format ///< [in] Code format - ); +__api int gn_fshift64(int64_t *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const int64_t *i, ///< [in] In-phase input array pointer + size_t i_size, ///< [in] In-phase input array size + const int64_t *q, ///< [in] Quadrature input array pointer + size_t q_size, ///< [in] Quadrature input array size + int n, ///< [in] Code width + double fs, ///< [in] Sample rate + double fshift, ///< [in] Shift frequency + GnCodeFormat format ///< [in] Code format +); /** * @brief gn_normalize16 * @return 0 on success, non-zero otherwise */ -__api int gn_normalize16( - double* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const int16_t* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - int n, ///< [in] Resolution - GnCodeFormat format ///< [in] Code format - ); +__api int gn_normalize16(double *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const int16_t *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + int n, ///< [in] Resolution + GnCodeFormat format ///< [in] Code format +); /** * @brief gn_normalize32 * @return 0 on success, non-zero otherwise */ -__api int gn_normalize32( - double* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const int32_t* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - int n, ///< [in] Resolution - GnCodeFormat format ///< [in] Code format - ); +__api int gn_normalize32(double *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const int32_t *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + int n, ///< [in] Resolution + GnCodeFormat format ///< [in] Code format +); /** * @brief gn_normalize64 * @return 0 on success, non-zero otherwise */ -__api int gn_normalize64( - double* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const int64_t* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - int n, ///< [in] Resolution - GnCodeFormat format ///< [in] Code format - ); +__api int gn_normalize64(double *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const int64_t *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + int n, ///< [in] Resolution + GnCodeFormat format ///< [in] Code format +); /** * @brief gn_polyval * @return 0 on success, non-zero otherwise */ -__api int gn_polyval( - double* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const double* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - const double* c, ///< [in] Coefficient array pointer - size_t c_size ///< [in] Coefficient array size - ); +__api int gn_polyval(double *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const double *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + const double *c, ///< [in] Coefficient array pointer + size_t c_size ///< [in] Coefficient array size +); /** * @brief gn_quantize16 * @return 0 on success, non-zero otherwise */ -__api int gn_quantize16( - int16_t* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const double* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - double fsr, ///< [in] Full-scale range - int n, ///< [in] Resolution - double noise, ///< [in] Input referred RMS noise - GnCodeFormat format ///< [in] Code format +__api int gn_quantize16(int16_t *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const double *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + double fsr, ///< [in] Full-scale range + int n, ///< [in] Resolution + double noise, ///< [in] Input referred RMS noise + GnCodeFormat format ///< [in] Code format ); /** * @brief gn_quantize32 * @return 0 on success, non-zero otherwise */ -__api int gn_quantize32( - int32_t* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const double* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - double fsr, ///< [in] Full-scale range - int n, ///< [in] Resolution - double noise, ///< [in] Input referred RMS noise - GnCodeFormat format ///< [in] Code format +__api int gn_quantize32(int32_t *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const double *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + double fsr, ///< [in] Full-scale range + int n, ///< [in] Resolution + double noise, ///< [in] Input referred RMS noise + GnCodeFormat format ///< [in] Code format ); /** * @brief gn_quantize64 * @return 0 on success, non-zero otherwise */ -__api int gn_quantize64( - int64_t* out, ///< [out] Output array pointer - size_t out_size, ///< [in] Output array size - const double* in, ///< [in] Input array pointer - size_t in_size, ///< [in] Input array size - double fsr, ///< [in] Full-scale range - int n, ///< [in] Resolution - double noise, ///< [in] Input referred RMS noise - GnCodeFormat format ///< [in] Code format +__api int gn_quantize64(int64_t *out, ///< [out] Output array pointer + size_t out_size, ///< [in] Output array size + const double *in, ///< [in] Input array pointer + size_t in_size, ///< [in] Input array size + double fsr, ///< [in] Full-scale range + int n, ///< [in] Resolution + double noise, ///< [in] Input referred RMS noise + GnCodeFormat format ///< [in] Code format ); /** @@ -1731,21 +1680,20 @@ __api int gn_quantize64( * @return 0 on success, non-zero otherwise */ __api int gn_downsample_size( - size_t* out_size, ///< [out] Output array size - size_t in_size, ///< [in] Input array size - int ratio, ///< [in] Downsample ratio - bool interleaved ///< [in] If bool, 'in' is interleaved I/Q data - ); + size_t *out_size, ///< [out] Output array size + size_t in_size, ///< [in] Input array size + int ratio, ///< [in] Downsample ratio + bool interleaved ///< [in] If bool, 'in' is interleaved I/Q data +); /** * @brief gn_fshift_size * @return 0 on success, non-zero otherwise */ -__api int gn_fshift_size( - size_t* out_size, ///< [out] Output array size - size_t i_size, ///< [in] In-phase input array size - size_t q_size ///< [in] Quadrature input array size - ); +__api int gn_fshift_size(size_t *out_size, ///< [out] Output array size + size_t i_size, ///< [in] In-phase input array size + size_t q_size ///< [in] Quadrature input array size +); /** @} SignalProcessingHelpers */ @@ -1769,59 +1717,56 @@ extern "C" { * @brief gn_cos * @return 0 on success, non-zero otherwise */ -__api int gn_cos( - double* out, ///< [out] Array pointer - size_t size, ///< [in] Array size - double fs, ///< [in] Sample rate (S/s) - double ampl, ///< [in] Amplitude - double freq, ///< [in] Frequency (Hz) - double phase, ///< [in] Phase (rad) - double td, ///< [in] Time delay (s) - double tj ///< [in] RMS Aperture jitter (s) - ); +__api int gn_cos(double *out, ///< [out] Array pointer + size_t size, ///< [in] Array size + double fs, ///< [in] Sample rate (S/s) + double ampl, ///< [in] Amplitude + double freq, ///< [in] Frequency (Hz) + double phase, ///< [in] Phase (rad) + double td, ///< [in] Time delay (s) + double tj ///< [in] RMS Aperture jitter (s) +); /** * @brief gn_gaussian * @return 0 on success, non-zero otherwise */ -__api int gn_gaussian( - double* out, ///< [out] Array pointer - size_t size, ///< [in] Array size - double mean, ///< [in] Mean - double sd ///< [in] Standard deviation - ); +__api int gn_gaussian(double *out, ///< [out] Array pointer + size_t size, ///< [in] Array size + double mean, ///< [in] Mean + double sd ///< [in] Standard deviation +); /** * @brief gn_ramp * @return 0 on success, non-zero otherwise */ -__api int gn_ramp( - double* out, ///< [out] Array pointer - size_t size, ///< [in] Array size - double start, ///< [in] Start value - double stop, ///< [in] Stop value - double noise ///< [in] RMS noise - ); +__api int gn_ramp(double *out, ///< [out] Array pointer + size_t size, ///< [in] Array size + double start, ///< [in] Start value + double stop, ///< [in] Stop value + double noise ///< [in] RMS noise +); /** * @brief gn_sin * @return 0 on success, non-zero otherwise */ -__api int gn_sin( - double* out, ///< [out] Array pointer - size_t size, ///< [in] Array size - double fs, ///< [in] Sample rate (S/s) - double ampl, ///< [in] Amplitude - double freq, ///< [in] Frequency (Hz) - double phase, ///< [in] Phase (rad) - double td, ///< [in] Time delay (s) - double tjrms ///< [in] RMS Aperture jitter (s) - ); +__api int gn_sin(double *out, ///< [out] Array pointer + size_t size, ///< [in] Array size + double fs, ///< [in] Sample rate (S/s) + double ampl, ///< [in] Amplitude + double freq, ///< [in] Frequency (Hz) + double phase, ///< [in] Phase (rad) + double td, ///< [in] Time delay (s) + double tjrms ///< [in] RMS Aperture jitter (s) +); /** * @brief gn_wf_analysis * @return 0 on success, non-zero otherwise - * @details The results contain the following key-value pairs (see general description of + * @details The results contain the following key-value pairs (see general + * description of * \ref AnalysisRoutines "Analysis Routines"). * *
Key Description @@ -1836,56 +1781,55 @@ __api int gn_sin( *
max_index Index of first occurence of maximum value *
*/ -__api int gn_wf_analysis( - char** rkeys, ///< [out] Result keys array pointer - size_t rkeys_size, ///< [in] Result keys array size - double* rvalues, ///< [out] Result values array pointer - size_t rvalues_size, ///< [in] Result values array size - const double* in, ///< [in] Waveform array pointer - size_t in_size ///< [in] Waveform array size - ); +__api int gn_wf_analysis(char **rkeys, ///< [out] Result keys array pointer + size_t rkeys_size, ///< [in] Result keys array size + double *rvalues, ///< [out] Result values array pointer + size_t rvalues_size, ///< [in] Result values array size + const double *in, ///< [in] Waveform array pointer + size_t in_size ///< [in] Waveform array size +); /** * @brief gn_wf_analysis16 * @return 0 on success, non-zero otherwise * @details See description of \ref gn_wf_analysis. */ -__api int gn_wf_analysis16( - char** rkeys, ///< [out] Result keys array pointer - size_t rkeys_size, ///< [in] Result keys array size - double* rvalues, ///< [out] Result values array pointer - size_t rvalues_size, ///< [in] Result values array size - const int16_t* in, ///< [in] Waveform array pointer - size_t in_size ///< [in] Waveform array size - ); +__api int +gn_wf_analysis16(char **rkeys, ///< [out] Result keys array pointer + size_t rkeys_size, ///< [in] Result keys array size + double *rvalues, ///< [out] Result values array pointer + size_t rvalues_size, ///< [in] Result values array size + const int16_t *in, ///< [in] Waveform array pointer + size_t in_size ///< [in] Waveform array size +); /** * @brief gn_wf_analysis32 * @return 0 on success, non-zero otherwise * @details See description of \ref gn_wf_analysis. */ -__api int gn_wf_analysis32( - char** rkeys, ///< [out] Result keys array pointer - size_t rkeys_size, ///< [in] Result keys array size - double* rvalues, ///< [out] Result values array pointer - size_t rvalues_size, ///< [in] Result values array size - const int32_t* in, ///< [in] Waveform array pointer - size_t in_size ///< [in] Waveform array size - ); +__api int +gn_wf_analysis32(char **rkeys, ///< [out] Result keys array pointer + size_t rkeys_size, ///< [in] Result keys array size + double *rvalues, ///< [out] Result values array pointer + size_t rvalues_size, ///< [in] Result values array size + const int32_t *in, ///< [in] Waveform array pointer + size_t in_size ///< [in] Waveform array size +); /** * @brief gn_wf_analysis64 * @return 0 on success, non-zero otherwise * @details See description of \ref gn_wf_analysis. */ -__api int gn_wf_analysis64( - char** rkeys, ///< [out] Result keys array pointer - size_t rkeys_size, ///< [in] Result keys array size - double* rvalues, ///< [out] Result values array pointer - size_t rvalues_size, ///< [in] Result values array size - const int64_t* in, ///< [in] Waveform array pointer - size_t in_size ///< [in] Waveform array size - ); +__api int +gn_wf_analysis64(char **rkeys, ///< [out] Result keys array pointer + size_t rkeys_size, ///< [in] Result keys array size + double *rvalues, ///< [out] Result values array pointer + size_t rvalues_size, ///< [in] Result values array size + const int64_t *in, ///< [in] Waveform array pointer + size_t in_size ///< [in] Waveform array size +); /** @} Waveforms */ diff --git a/bindings/c/include/cgenalyzer_private.h b/bindings/c/include/cgenalyzer_private.h index 1d0e41a..76619e8 100644 --- a/bindings/c/include/cgenalyzer_private.h +++ b/bindings/c/include/cgenalyzer_private.h @@ -1,25 +1,6 @@ -/* - * cgenalyzer_private - genalyzer private header file - * - * Copyright (C) 2022 Analog Devices, Inc. - * Author: Srikanth Pagadarai - * - * 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. - * */ - - +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef CGENALYZER_PRIVATE_H #define CGENALYZER_PRIVATE_H #include "cgenalyzer_simplified_beta.h" @@ -33,10 +14,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -62,170 +43,158 @@ namespace gn = ::genalyzer_impl; namespace util { - class log - { - public: - - log() - : m_log {}, - m_flag {false} - {} - - public: - - bool check() - { - return m_flag; - } - - void clear() - { - m_log.clear(); - m_flag = false; - } - - std::string_view get() const - { - return m_log; - } - - void set(const char* msg) - { - m_log = msg; - m_flag = true; - } - - size_t size() const - { - return m_log.size(); - } - - public: - - void append() {} - - template - void append(const char* s, Types... the_rest) - { - m_log.append(s); - append(the_rest...); - } - - void prepend() {} - - template - void prepend(const char* s, Types... the_rest) - { - prepend(the_rest...); - m_log.insert(0, s); - } - - private: - - std::string m_log; - bool m_flag; - - }; // class log - - static log gn_error_log; - - template - int return_on_exception(const char* s, Types... the_rest) - { - gn_error_log.set(s); - gn_error_log.append(the_rest...); - return gn_failure; - } - - template - int check_pointer(const T* p) - { - if (nullptr == p) { - throw std::runtime_error("check_pointer : pointer is NULL"); - } - return gn_success; - } - - size_t terminated_size(size_t string_size); - void fill_string_buffer( - const char* src, // Pointer to source - size_t src_size, // Size of source; should not count null-terminator, if it exists - char* dst, // Pointer to destination - size_t dst_size // Size of destination - ); - std::string get_object_key_from_filename(const std::string& filename); +class log { +public: + log() : + m_log{}, m_flag{ false } { + } + +public: + bool check() { + return m_flag; + } + + void clear() { + m_log.clear(); + m_flag = false; + } + + std::string_view get() const { + return m_log; + } + + void set(const char *msg) { + m_log = msg; + m_flag = true; + } + + size_t size() const { + return m_log.size(); + } + +public: + void append() { + } + + template + void append(const char *s, Types... the_rest) { + m_log.append(s); + append(the_rest...); + } + + void prepend() { + } + + template + void prepend(const char *s, Types... the_rest) { + prepend(the_rest...); + m_log.insert(0, s); + } + +private: + std::string m_log; + bool m_flag; + +}; // class log + +static log gn_error_log; + +template +int return_on_exception(const char *s, Types... the_rest) { + gn_error_log.set(s); + gn_error_log.append(the_rest...); + return gn_failure; } +template +int check_pointer(const T *p) { + if (nullptr == p) { + throw std::runtime_error("check_pointer : pointer is NULL"); + } + return gn_success; +} + +size_t terminated_size(size_t string_size); +void fill_string_buffer( + const char *src, // Pointer to source + size_t src_size, // Size of source; should not count null-terminator, if it + // exists + char *dst, // Pointer to destination + size_t dst_size // Size of destination +); +std::string get_object_key_from_filename(const std::string &filename); +} // namespace util + #ifdef __cplusplus extern "C" { #endif - using namespace genalyzer_impl; - - struct gn_config_private { - bool _gn_config_calloced = false; - - // waveform and FFT settings - tone_type ttype; - gn::size_t npts; - gn::real_t sample_rate; - gn::real_t *tone_freq; - gn::real_t *tone_ampl; - gn::real_t *tone_phase; - gn::size_t num_tones; - gn::real_t fsr; - int qres; - gn::real_t noise_rms; - GnCodeFormat code_format; - gn::size_t nfft; - gn::size_t fft_navg; - GnFreqAxisType axis_type; - gn::real_t data_rate; - gn::real_t shift_freq; - GnWindow win; - gn::real_t ramp_start; - gn::real_t ramp_stop; - - // analysis settings - char *obj_key; - char *comp_key; - int ssb_fund; - int ssb_rest; - int max_harm_order; - GnDnlSignal dnla_signal_type; - GnInlLineFit inla_fit; - gn::size_t _code_density_size; - - // keys, values and sizes for Fourier analysis results - char **_fa_result_keys; - gn::real_t *_fa_result_values; - gn::size_t *_fa_result_key_sizes; - gn::size_t _fa_results_size; - - // keys, values and sizes for waveform analysis results - char **_wfa_result_keys; - gn::real_t *_wfa_result_values; - gn::size_t *_wfa_result_key_sizes; - gn::size_t _wfa_results_size; - - // keys, values and sizes for histogram results - char **_hist_result_keys; - gn::real_t *_hist_result_values; - gn::size_t *_hist_result_key_sizes; - gn::size_t _hist_results_size; - - // keys, values and sizes for DNL results - char **_dnl_result_keys; - gn::real_t *_dnl_result_values; - gn::size_t *_dnl_result_key_sizes; - gn::size_t _dnl_results_size; - - // keys, values and sizes for INL results - char **_inl_result_keys; - gn::real_t *_inl_result_values; - gn::size_t *_inl_result_key_sizes; - gn::size_t _inl_results_size; - }; +using namespace genalyzer_impl; + +struct gn_config_private { + bool _gn_config_calloced = false; + + // waveform and FFT settings + tone_type ttype; + gn::size_t npts; + gn::real_t sample_rate; + gn::real_t *tone_freq; + gn::real_t *tone_ampl; + gn::real_t *tone_phase; + gn::size_t num_tones; + gn::real_t fsr; + int qres; + gn::real_t noise_rms; + GnCodeFormat code_format; + gn::size_t nfft; + gn::size_t fft_navg; + GnFreqAxisType axis_type; + gn::real_t data_rate; + gn::real_t shift_freq; + GnWindow win; + gn::real_t ramp_start; + gn::real_t ramp_stop; + + // analysis settings + char *obj_key; + char *comp_key; + int ssb_fund; + int ssb_rest; + int max_harm_order; + GnDnlSignal dnla_signal_type; + GnInlLineFit inla_fit; + gn::size_t _code_density_size; + + // keys, values and sizes for Fourier analysis results + char **_fa_result_keys; + gn::real_t *_fa_result_values; + gn::size_t *_fa_result_key_sizes; + gn::size_t _fa_results_size; + + // keys, values and sizes for waveform analysis results + char **_wfa_result_keys; + gn::real_t *_wfa_result_values; + gn::size_t *_wfa_result_key_sizes; + gn::size_t _wfa_results_size; + + // keys, values and sizes for histogram results + char **_hist_result_keys; + gn::real_t *_hist_result_values; + gn::size_t *_hist_result_key_sizes; + gn::size_t _hist_results_size; + + // keys, values and sizes for DNL results + char **_dnl_result_keys; + gn::real_t *_dnl_result_values; + gn::size_t *_dnl_result_key_sizes; + gn::size_t _dnl_results_size; + + // keys, values and sizes for INL results + char **_inl_result_keys; + gn::real_t *_inl_result_values; + gn::size_t *_inl_result_key_sizes; + gn::size_t _inl_results_size; +}; #ifdef __cplusplus } diff --git a/bindings/c/include/cgenalyzer_simplified_beta.h b/bindings/c/include/cgenalyzer_simplified_beta.h index d1d9c73..3e7529f 100644 --- a/bindings/c/include/cgenalyzer_simplified_beta.h +++ b/bindings/c/include/cgenalyzer_simplified_beta.h @@ -1,25 +1,6 @@ -/* - * cgenalyzer - genalyzer (beta) simplified API header file - * - * Copyright (C) 2022 Analog Devices, Inc. - * Author: Srikanth Pagadarai - * - * 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. - * */ - - +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef CGENALYZER_SIMPLIFIED_BETA_H #define CGENALYZER_SIMPLIFIED_BETA_H #include "cgenalyzer.h" @@ -27,8 +8,7 @@ #include #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif #ifdef _WIN32 @@ -37,587 +17,475 @@ extern "C" #else #define __api __declspec(dllimport) #endif -#elif __GNUC__ >= 4 && !defined(MATLAB_MEX_FILE) \ - && !defined(MATLAB_LOADLIBRARY) -#define __api __attribute__ ((visibility ("default"))) +#elif __GNUC__ >= 4 && !defined(MATLAB_MEX_FILE) && !defined(MATLAB_LOADLIBRARY) +#define __api __attribute__((visibility("default"))) #else #define __api #endif - - // opaque pointer - typedef struct gn_config_private *gn_config; - - typedef enum tone_type - { - REAL_COSINE, - REAL_SINE, - COMPLEX_EXP - } tone_type; - - /** - * @brief free memory for configuration struct - * @return 0 on success, non-zero otherwise - * @param c genalyzer Configuration struct - */ - __api int gn_config_free( - gn_config *c - ); - - /** - * @brief set configuration struct member: tone_type - * @return 0 on success, non-zero otherwise - * @param ttype ENUM value to indicate input tone type. Options: REAL_COSINE, REAL_SINE, COMPLEX_EXP - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_ttype( - tone_type ttype, - gn_config *c - ); - - /** - * @brief set configuration struct member: npts - * @return 0 on success, non-zero otherwise - * @param npts Number of sample points in the generated waveform - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_npts( - size_t npts, - gn_config *c - ); - - /** - * @brief get configuration struct member: npts - * @return 0 on success, non-zero otherwise - * @param npts Number of sample points in the generated waveform - * @param c genalyzer Configuration struct - */ - __api int gn_config_get_npts( - size_t *npts, - gn_config *c - ); - - /** - * @brief set configuration struct member: sample_rate - * @return 0 on success, non-zero otherwise - * @param sample_rate Input Sample rate of the data converter - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_sample_rate( - double sample_rate, - gn_config *c - ); - - /** - * @brief get configuration struct member: sample_rate - * @return 0 on success, non-zero otherwise - * @param sample_rate Input Sample rate of the data converter - * @param c genalyzer Configuration struct - */ - __api int gn_config_get_sample_rate( - double *sample_rate, - gn_config *c - ); - - /** - * @brief set configuration struct member: data_rate - * @return 0 on success, non-zero otherwise - * @param data_rate Input data rate of the data converter - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_data_rate( - double data_rate, - gn_config *c - ); - - /** - * @brief set configuration struct member: shift_freq - * @return 0 on success, non-zero otherwise - * @param shift_freq Shift frequency of the data converter - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_shift_freq( - double shift_freq, - gn_config *c - ); - - /** - * @brief set configuration struct member: num_tones - * @return 0 on success, non-zero otherwise - * @param num_tones Number of tones to generate - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_num_tones( - size_t num_tones, - gn_config *c - ); - - /** - * @brief set configuration struct member: tone_freq - * @return 0 on success, non-zero otherwise - * @param tone_freq Input array of tone frequencies to generate - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_tone_freq( - double *tone_freq, - gn_config *c - ); - - /** - * @brief set configuration struct member: tone_ampl - * @return 0 on success, non-zero otherwise - * @param tone_ampl Input array of tone scales to generate - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_tone_ampl( - double *tone_ampl, - gn_config *c - ); - - /** - * @brief set configuration struct member: tone_phase - * @return 0 on success, non-zero otherwise - * @param tone_phase Input array of tone phases to generate - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_tone_phase( - double *tone_phase, - gn_config *c - ); - - /** - * @brief set configuration struct member: fsr - * @return 0 on success, non-zero otherwise - * @param fsr Full-scale range of the waveform - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_fsr( - double fsr, - gn_config *c - ); - - /** - * @brief set configuration struct member: qres - * @return 0 on success, non-zero otherwise - * @param qres Quantization resolution - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_qres( - int qres, - gn_config *c - ); - - /** - * @brief set configuration struct member: noise_rms - * @return 0 on success, non-zero otherwise - * @param noise_rms RMS Noise - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_noise_rms( - double noise_rms, - gn_config *c - ); - - /** - * @brief set configuration struct member: code_format - * @return 0 on success, non-zero otherwise - * @param code_format Code format of data - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_code_format( - GnCodeFormat code_format, - gn_config *c - ); - - /** - * @brief set configuration struct member: nfft - * @return 0 on success, non-zero otherwise - * @param nfft FFT order - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_nfft( - size_t nfft, - gn_config *c - ); - - /** - * @brief get configuration struct member: nfft - * @return 0 on success, non-zero otherwise - * @param nfft FFT order - * @param c genalyzer Configuration struct - */ - __api int gn_config_get_nfft( - size_t *nfft, - gn_config *c - ); - - /** - * @brief set configuration struct member: navg - * @return 0 on success, non-zero otherwise - * @param fft_navg Num. of FFTs to average - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_fft_navg( - size_t fft_navg, - gn_config *c - ); - - /** - * @brief set configuration struct member: win - * @return 0 on success, non-zero otherwise - * @param win Window function used - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_win( - GnWindow win, - gn_config *c - ); - - /** - * @brief set configuration struct member: ssb_fund - * @return 0 on success, non-zero otherwise - * @param ssb_fund Single side bin fundamental - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_ssb_fund( - int ssb_fund, - gn_config *c - ); - - /** - * @brief set configuration struct member: ssb_rest - * @return 0 on success, non-zero otherwise - * @param ssb_rest Single side bins rest - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_ssb_rest( - int ssb_rest, - gn_config *c - ); - - /** - * @brief set configuration struct member: max_harm_order - * @return 0 on success, non-zero otherwise - * @param max_harm_order Max order of harmonic - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_max_harm_order( - int max_harm_order, - gn_config *c - ); - - /** - * @brief set configuration struct member: dnla_signal_type - * @return 0 on success, non-zero otherwise - * @param dnla_signal_type DNL analysis signal type - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_dnla_signal_type( - GnDnlSignal dnla_signal_type, - gn_config *c - ); - - /** - * @brief set configuration struct member: inla_fit - * @return 0 on success, non-zero otherwise - * @param inla_fit INL analysis line fit - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_inla_fit( - GnInlLineFit inla_fit, - gn_config *c - ); - - /** - * @brief set configuration struct member: ramp_start - * @return 0 on success, non-zero otherwise - * @param ramp_start start value of ramp - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_ramp_start( - double ramp_start, - gn_config *c - ); - - /** - * @brief set configuration struct member: ramp_stop - * @return 0 on success, non-zero otherwise - * @param ramp_stop stop value of ramp - * @param c genalyzer Configuration struct - */ - __api int gn_config_set_ramp_stop( - double ramp_stop, - gn_config *c - ); - - /** - * @brief get configuration struct member: _code_density_size - * @return 0 on success, non-zero otherwise - * @param code_density_size code density size - * @param c genalyzer Configuration struct - */ - __api int gn_config_get_code_density_size( - size_t *code_density_size, - gn_config *c - ); - - /** - * @brief Configure tone parameters to be used in measurement - * @return 0 on success, non-zero otherwise - * @param ttype ENUM value to indicate input tone type. Options: REAL_COSINE, REAL_SINE, COMPLEX_EXP - * @param npts Number of sample points in the generated waveform - * @param sample_rate Input Sample rate of the data converter - * @param num_tones Number of tones to generate - * @param tone_freq Input array of tone frequencies to generate - * @param tone_ampl Input array of tone scales to generate - * @param tone_phase Input array of tone phases to generate - * @param c Configuration struct containing tone parameters - */ - __api int gn_config_gen_tone ( - tone_type ttype, - size_t npts, - double sample_rate, - size_t num_tones, - double *tone_freq, - double *tone_ampl, - double *tone_phase, - gn_config *c - ); - - /** - * @brief Configure tone parameters to be used in measurement - * @return 0 on success, non-zero otherwise - * @param npts Number of sample points in the generated waveform - * @param ramp_start Input start value of ramp - * @param ramp_stop Input stop value of ramp - * @param c Configuration struct containing ramp parameters - */ - __api int gn_config_gen_ramp( - size_t npts, - double ramp_start, - double ramp_stop, - gn_config *c - ); - - /** - * @brief Configure quantization parameters to be used in measurement - * @return 0 on success, non-zero otherwise - * @param npts Number of sample points in the generated waveform - * @param fsr Full-scale range of the waveform - * @param qres Quantization resolution - * @param qnoise Quantization noise - * @param c Configuration structure - */ - __api int gn_config_quantize( - size_t npts, - double fsr, - int qres, - double qnoise, - gn_config *c - ); - - /** - * @brief Configure parameters to compute histogram - * @return 0 on success, non-zero otherwise - * @param npts Number of sample points in the generated waveform - * @param qres Quantization resolution - * @param c Configuration structure - */ - __api int gn_config_histz_nla( - size_t npts, - int qres, - gn_config *c - ); - - /** - * @brief Configure FFT parameters - * @return 0 on success, non-zero otherwise - */ - __api int gn_config_fftz( - size_t npts, ///< [npts] Number of sample points in the input waveform - int qres, ///< [qres] Quantization resolution - size_t navg, ///< [navg] Number of FFT averages - size_t nfft, ///< [nfft] FFT order - GnWindow win, ///< [win] Window function to apply, Options: GnWindowBlackmanHarris, GnWindowHann, GnWindowNoWindow - gn_config *c ///< [c] Configuration structure containing test parameters - ); - - /** - * @brief Generate sinusoidal tone based on supplied configuration. - * @return 0 on success, non-zero otherwise - */ - __api int gn_config_fa( - double fixed_tone_freq, ///< [fixed_tone_freq] Fixed tone frequency - gn_config *c ///< [c] Configuration structure containing test parameters - ); - - /** - * @brief Generate sinusoidal tone based on supplied configuration without specifying tone manually. - * @return 0 on success, non-zero otherwise - */ - __api int gn_config_fa_auto( - uint8_t ssb_width, ///< [ssb_width] Number of bins to use for fundamental search and keepout of other tones - gn_config *c ///< [c] Configuration structure containing test parameters - ); - - /** - * @brief Generate ramp based on supplied configuration. - * @param out Output array of ramp generated - * @param c Configuration structure of test and waveform to generate - */ - __api int gn_gen_ramp( - double **out, - gn_config *c - ); - - /** - * @brief Generate sinusoidal tone based on supplied configuration. - * @return 0 on success, non-zero otherwise - * @param out Output array of generated tone - * @param c Configuration structure containing test parameters - */ - __api int gn_gen_real_tone( - double **out, - gn_config *c - ); - - /** - * @brief Generate sinusoidal tone based on supplied configuration. - * @return 0 on success, non-zero otherwise - * @param outi In-phase output array of generated tone - * @param outq Quadrature output array of generated tone - * @param c Configuration structure containing test parameters - */ - __api int gn_gen_complex_tone( - double **outi, - double **outq, - gn_config *c - ); - - /** - * @brief Quantize waveform based on supplied configuration. - * @return 0 on success, non-zero otherwise - */ - __api int gn_quantize( - int32_t **out, ///< [out] Quantized output waveform - const double *in, ///< [in] Input waveform to be quantized - gn_config *c ///< [c] Configuration structure containing test parameters - ); - /** + +// opaque pointer +typedef struct gn_config_private *gn_config; + +typedef enum tone_type { REAL_COSINE, + REAL_SINE, + COMPLEX_EXP } tone_type; + +/** + * @brief free memory for configuration struct + * @return 0 on success, non-zero otherwise + * @param c genalyzer Configuration struct + */ +__api int gn_config_free(gn_config *c); + +/** + * @brief set configuration struct member: tone_type + * @return 0 on success, non-zero otherwise + * @param ttype ENUM value to indicate input tone type. Options: REAL_COSINE, + * REAL_SINE, COMPLEX_EXP + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_ttype(tone_type ttype, gn_config *c); + +/** + * @brief set configuration struct member: npts + * @return 0 on success, non-zero otherwise + * @param npts Number of sample points in the generated waveform + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_npts(size_t npts, gn_config *c); + +/** + * @brief get configuration struct member: npts + * @return 0 on success, non-zero otherwise + * @param npts Number of sample points in the generated waveform + * @param c genalyzer Configuration struct + */ +__api int gn_config_get_npts(size_t *npts, gn_config *c); + +/** + * @brief set configuration struct member: sample_rate + * @return 0 on success, non-zero otherwise + * @param sample_rate Input Sample rate of the data converter + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_sample_rate(double sample_rate, gn_config *c); + +/** + * @brief get configuration struct member: sample_rate + * @return 0 on success, non-zero otherwise + * @param sample_rate Input Sample rate of the data converter + * @param c genalyzer Configuration struct + */ +__api int gn_config_get_sample_rate(double *sample_rate, gn_config *c); + +/** + * @brief set configuration struct member: data_rate + * @return 0 on success, non-zero otherwise + * @param data_rate Input data rate of the data converter + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_data_rate(double data_rate, gn_config *c); + +/** + * @brief set configuration struct member: shift_freq + * @return 0 on success, non-zero otherwise + * @param shift_freq Shift frequency of the data converter + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_shift_freq(double shift_freq, gn_config *c); + +/** + * @brief set configuration struct member: num_tones + * @return 0 on success, non-zero otherwise + * @param num_tones Number of tones to generate + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_num_tones(size_t num_tones, gn_config *c); + +/** + * @brief set configuration struct member: tone_freq + * @return 0 on success, non-zero otherwise + * @param tone_freq Input array of tone frequencies to generate + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_tone_freq(double *tone_freq, gn_config *c); + +/** + * @brief set configuration struct member: tone_ampl + * @return 0 on success, non-zero otherwise + * @param tone_ampl Input array of tone scales to generate + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_tone_ampl(double *tone_ampl, gn_config *c); + +/** + * @brief set configuration struct member: tone_phase + * @return 0 on success, non-zero otherwise + * @param tone_phase Input array of tone phases to generate + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_tone_phase(double *tone_phase, gn_config *c); + +/** + * @brief set configuration struct member: fsr + * @return 0 on success, non-zero otherwise + * @param fsr Full-scale range of the waveform + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_fsr(double fsr, gn_config *c); + +/** + * @brief set configuration struct member: qres + * @return 0 on success, non-zero otherwise + * @param qres Quantization resolution + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_qres(int qres, gn_config *c); + +/** + * @brief set configuration struct member: noise_rms + * @return 0 on success, non-zero otherwise + * @param noise_rms RMS Noise + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_noise_rms(double noise_rms, gn_config *c); + +/** + * @brief set configuration struct member: code_format + * @return 0 on success, non-zero otherwise + * @param code_format Code format of data + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_code_format(GnCodeFormat code_format, gn_config *c); + +/** + * @brief set configuration struct member: nfft + * @return 0 on success, non-zero otherwise + * @param nfft FFT order + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_nfft(size_t nfft, gn_config *c); + +/** + * @brief get configuration struct member: nfft + * @return 0 on success, non-zero otherwise + * @param nfft FFT order + * @param c genalyzer Configuration struct + */ +__api int gn_config_get_nfft(size_t *nfft, gn_config *c); + +/** + * @brief set configuration struct member: navg + * @return 0 on success, non-zero otherwise + * @param fft_navg Num. of FFTs to average + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_fft_navg(size_t fft_navg, gn_config *c); + +/** + * @brief set configuration struct member: win + * @return 0 on success, non-zero otherwise + * @param win Window function used + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_win(GnWindow win, gn_config *c); + +/** + * @brief set configuration struct member: ssb_fund + * @return 0 on success, non-zero otherwise + * @param ssb_fund Single side bin fundamental + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_ssb_fund(int ssb_fund, gn_config *c); + +/** + * @brief set configuration struct member: ssb_rest + * @return 0 on success, non-zero otherwise + * @param ssb_rest Single side bins rest + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_ssb_rest(int ssb_rest, gn_config *c); + +/** + * @brief set configuration struct member: max_harm_order + * @return 0 on success, non-zero otherwise + * @param max_harm_order Max order of harmonic + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_max_harm_order(int max_harm_order, gn_config *c); + +/** + * @brief set configuration struct member: dnla_signal_type + * @return 0 on success, non-zero otherwise + * @param dnla_signal_type DNL analysis signal type + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_dnla_signal_type(GnDnlSignal dnla_signal_type, + gn_config *c); + +/** + * @brief set configuration struct member: inla_fit + * @return 0 on success, non-zero otherwise + * @param inla_fit INL analysis line fit + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_inla_fit(GnInlLineFit inla_fit, gn_config *c); + +/** + * @brief set configuration struct member: ramp_start + * @return 0 on success, non-zero otherwise + * @param ramp_start start value of ramp + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_ramp_start(double ramp_start, gn_config *c); + +/** + * @brief set configuration struct member: ramp_stop + * @return 0 on success, non-zero otherwise + * @param ramp_stop stop value of ramp + * @param c genalyzer Configuration struct + */ +__api int gn_config_set_ramp_stop(double ramp_stop, gn_config *c); + +/** + * @brief get configuration struct member: _code_density_size + * @return 0 on success, non-zero otherwise + * @param code_density_size code density size + * @param c genalyzer Configuration struct + */ +__api int gn_config_get_code_density_size(size_t *code_density_size, + gn_config *c); + +/** + * @brief Configure tone parameters to be used in measurement + * @return 0 on success, non-zero otherwise + * @param ttype ENUM value to indicate input tone type. Options: REAL_COSINE, + * REAL_SINE, COMPLEX_EXP + * @param npts Number of sample points in the generated waveform + * @param sample_rate Input Sample rate of the data converter + * @param num_tones Number of tones to generate + * @param tone_freq Input array of tone frequencies to generate + * @param tone_ampl Input array of tone scales to generate + * @param tone_phase Input array of tone phases to generate + * @param c Configuration struct containing tone parameters + */ +__api int gn_config_gen_tone(tone_type ttype, size_t npts, double sample_rate, + size_t num_tones, double *tone_freq, + double *tone_ampl, double *tone_phase, + gn_config *c); + +/** + * @brief Configure tone parameters to be used in measurement + * @return 0 on success, non-zero otherwise + * @param npts Number of sample points in the generated waveform + * @param ramp_start Input start value of ramp + * @param ramp_stop Input stop value of ramp + * @param c Configuration struct containing ramp parameters + */ +__api int gn_config_gen_ramp(size_t npts, double ramp_start, double ramp_stop, + gn_config *c); + +/** + * @brief Configure quantization parameters to be used in measurement + * @return 0 on success, non-zero otherwise + * @param npts Number of sample points in the generated waveform + * @param fsr Full-scale range of the waveform + * @param qres Quantization resolution + * @param qnoise Quantization noise + * @param c Configuration structure + */ +__api int gn_config_quantize(size_t npts, double fsr, int qres, double qnoise, + gn_config *c); + +/** + * @brief Configure parameters to compute histogram + * @return 0 on success, non-zero otherwise + * @param npts Number of sample points in the generated waveform + * @param qres Quantization resolution + * @param c Configuration structure + */ +__api int gn_config_histz_nla(size_t npts, int qres, gn_config *c); + +/** + * @brief Configure FFT parameters + * @return 0 on success, non-zero otherwise + */ +__api int gn_config_fftz( + size_t npts, ///< [npts] Number of sample points in the input waveform + int qres, ///< [qres] Quantization resolution + size_t navg, ///< [navg] Number of FFT averages + size_t nfft, ///< [nfft] FFT order + GnWindow win, ///< [win] Window function to apply, Options: + ///< GnWindowBlackmanHarris, GnWindowHann, GnWindowNoWindow + gn_config *c ///< [c] Configuration structure containing test parameters +); + +/** + * @brief Generate sinusoidal tone based on supplied configuration. + * @return 0 on success, non-zero otherwise + */ +__api int gn_config_fa( + double fixed_tone_freq, ///< [fixed_tone_freq] Fixed tone frequency + gn_config *c ///< [c] Configuration structure containing test parameters +); + +/** + * @brief Generate sinusoidal tone based on supplied configuration without + * specifying tone manually. + * @return 0 on success, non-zero otherwise + */ +__api int gn_config_fa_auto( + uint8_t ssb_width, ///< [ssb_width] Number of bins to use for fundamental + ///< search and keepout of other tones + gn_config *c ///< [c] Configuration structure containing test parameters +); + +/** + * @brief Generate ramp based on supplied configuration. + * @param out Output array of ramp generated + * @param c Configuration structure of test and waveform to generate + */ +__api int gn_gen_ramp(double **out, gn_config *c); + +/** + * @brief Generate sinusoidal tone based on supplied configuration. + * @return 0 on success, non-zero otherwise + * @param out Output array of generated tone + * @param c Configuration structure containing test parameters + */ +__api int gn_gen_real_tone(double **out, gn_config *c); + +/** + * @brief Generate sinusoidal tone based on supplied configuration. + * @return 0 on success, non-zero otherwise + * @param outi In-phase output array of generated tone + * @param outq Quadrature output array of generated tone + * @param c Configuration structure containing test parameters + */ +__api int gn_gen_complex_tone(double **outi, double **outq, gn_config *c); + +/** + * @brief Quantize waveform based on supplied configuration. + * @return 0 on success, non-zero otherwise + */ +__api int gn_quantize( + int32_t **out, ///< [out] Quantized output waveform + const double *in, ///< [in] Input waveform to be quantized + gn_config *c ///< [c] Configuration structure containing test parameters +); +/** * @brief Compute FFT of quantized input waveform * @return 0 on success, non-zero otherwise */ - __api int gn_fftz( - double **out, ///< [out] Interleaved Re/Im FFT output - const int32_t *in_i, ///< [in_i] In-phase input - const int32_t *in_q, ///< [in_q] Quadrature input - gn_config *c ///< [c] Configuration structure containing test parameters - ); - - /** - * @brief Compute histogram of quantized waveform - * @return 0 on success, non-zero otherwise - */ - __api int gn_histz( - uint64_t **hist, ///< [hist] Output - Histogram of input quantized waveform - size_t *hist_len, ///< [hist_len] Output - Histogram size - const int32_t *qwf, ///< [qwf] Input - Quantized input waveform - gn_config *c ///< [c] Input - Configuration structure containing test parameters - ); - - /** - * @brief Compute histogram of quantized waveform - * @return 0 on success, non-zero otherwise - */ - __api int gn_dnlz( - double **dnl, - size_t *dnl_len, - const uint64_t *hist, - gn_config *c - ); - - /** - * @brief Compute histogram of quantized waveform - * @return 0 on success, non-zero otherwise - */ - - __api int gn_inlz( - double **inl, - size_t *inl_len, - const double *dnl, - gn_config *c - ); - - /** - * @brief Do waveform analysis and all get results - * @return 0 on success, non-zero otherwise - */ - __api int gn_get_wfa_results( - char ***rkeys, - double **rvalues, - size_t *results_size, ///< [results_size] size of results - const int32_t *qwf, ///< [qwf] Input - Quantized input array pointer - gn_config *c ///< [c] Input - Configuration structure containing test parameters - ); - - /** - * @brief Do histogram analysis and get results - * @return 0 on success, non-zero otherwise - */ - __api int gn_get_ha_results( - char ***rkeys, ///< [rkeys] Output - Result keys - double **rvalues, ///< [rvalues] Output - Result values - size_t *results_size, ///< [results_size] Output - Size of results - const uint64_t *hist, ///< [hist] Input - Histogram input to be analyzed - gn_config *c ///< [c] Input - Configuration structure containing test parameters - ); - - /** - * @brief Do DNL analysis and get results - * @return 0 on success, non-zero otherwise - */ - __api int gn_get_dnla_results( - char ***rkeys, ///< [rkeys] Output - Result keys - double **rvalues, ///< [rvalues] Output - Result values - size_t *results_size, ///< [results_size] Output - Size of results - const double *dnl, ///< [dnl] Input - DNL input to be analyzed - gn_config *c ///< [c] Input - Configuration structure containing test parameters - ); - - /** - * @brief Do INL analysis and get results - * @return 0 on success, non-zero otherwise - */ - __api int gn_get_inla_results( - char ***rkeys, ///< [rkeys] Output - Result keys - double **rvalues, ///< [rvalues] Output - Result values - size_t *results_size, ///< [results_size] Output - Size of results - const double *inl, ///< [dnl] Input - INL input to be analyzed - gn_config *c ///< [c] Input - Configuration structure containing test parameters - ); - - /** - * @brief Do Fourier analysis and get a single result - * @return 0 on success, non-zero otherwise - */ - __api int gn_get_fa_single_result( - double *rvalue, - const char* metric_name, - double *fft_ilv, ///< [fft_ilv] Input - Interleaved Re/Im array pointer - gn_config *c ///< [c] Input - Configuration structure containing test parameters - ); - - /** - * @brief Do Fourier analysis and all get results - * @return 0 on success, non-zero otherwise - */ - __api int gn_get_fa_results( - char ***rkeys, - double **rvalues, - size_t *results_size, ///< [results_size] size of results - double *fft_ilv, ///< [fft_ilv] Input - Interleaved Re/Im array pointer - gn_config *c ///< [c] Input - Configuration structure containing test parameters - ); - +__api int +gn_fftz(double **out, ///< [out] Interleaved Re/Im FFT output + const int32_t *in_i, ///< [in_i] In-phase input + const int32_t *in_q, ///< [in_q] Quadrature input + gn_config *c ///< [c] Configuration structure containing test parameters +); + +/** + * @brief Compute histogram of quantized waveform + * @return 0 on success, non-zero otherwise + */ +__api int gn_histz( + uint64_t ** + hist, ///< [hist] Output - Histogram of input quantized waveform + size_t *hist_len, ///< [hist_len] Output - Histogram size + const int32_t *qwf, ///< [qwf] Input - Quantized input waveform + gn_config * + c ///< [c] Input - Configuration structure containing test parameters +); + +/** + * @brief Compute histogram of quantized waveform + * @return 0 on success, non-zero otherwise + */ +__api int gn_dnlz(double **dnl, size_t *dnl_len, const uint64_t *hist, + gn_config *c); + +/** + * @brief Compute histogram of quantized waveform + * @return 0 on success, non-zero otherwise + */ + +__api int gn_inlz(double **inl, size_t *inl_len, const double *dnl, + gn_config *c); + +/** + * @brief Do waveform analysis and all get results + * @return 0 on success, non-zero otherwise + */ +__api int gn_get_wfa_results( + char ***rkeys, double **rvalues, + size_t *results_size, ///< [results_size] size of results + const int32_t *qwf, ///< [qwf] Input - Quantized input array pointer + gn_config * + c ///< [c] Input - Configuration structure containing test parameters +); + +/** + * @brief Do histogram analysis and get results + * @return 0 on success, non-zero otherwise + */ +__api int gn_get_ha_results( + char ***rkeys, ///< [rkeys] Output - Result keys + double **rvalues, ///< [rvalues] Output - Result values + size_t *results_size, ///< [results_size] Output - Size of results + const uint64_t *hist, ///< [hist] Input - Histogram input to be analyzed + gn_config * + c ///< [c] Input - Configuration structure containing test parameters +); + +/** + * @brief Do DNL analysis and get results + * @return 0 on success, non-zero otherwise + */ +__api int gn_get_dnla_results( + char ***rkeys, ///< [rkeys] Output - Result keys + double **rvalues, ///< [rvalues] Output - Result values + size_t *results_size, ///< [results_size] Output - Size of results + const double *dnl, ///< [dnl] Input - DNL input to be analyzed + gn_config * + c ///< [c] Input - Configuration structure containing test parameters +); + +/** + * @brief Do INL analysis and get results + * @return 0 on success, non-zero otherwise + */ +__api int gn_get_inla_results( + char ***rkeys, ///< [rkeys] Output - Result keys + double **rvalues, ///< [rvalues] Output - Result values + size_t *results_size, ///< [results_size] Output - Size of results + const double *inl, ///< [dnl] Input - INL input to be analyzed + gn_config * + c ///< [c] Input - Configuration structure containing test parameters +); + +/** + * @brief Do Fourier analysis and get a single result + * @return 0 on success, non-zero otherwise + */ +__api int gn_get_fa_single_result( + double *rvalue, const char *metric_name, + double *fft_ilv, ///< [fft_ilv] Input - Interleaved Re/Im array pointer + gn_config * + c ///< [c] Input - Configuration structure containing test parameters +); + +/** + * @brief Do Fourier analysis and all get results + * @return 0 on success, non-zero otherwise + */ +__api int gn_get_fa_results( + char ***rkeys, double **rvalues, + size_t *results_size, ///< [results_size] size of results + double *fft_ilv, ///< [fft_ilv] Input - Interleaved Re/Im array pointer + gn_config * + c ///< [c] Input - Configuration structure containing test parameters +); + #ifdef __cplusplus } #endif diff --git a/bindings/c/src/CMakeLists.txt b/bindings/c/src/CMakeLists.txt index 45c70e7..d579528 100644 --- a/bindings/c/src/CMakeLists.txt +++ b/bindings/c/src/CMakeLists.txt @@ -53,11 +53,11 @@ configure_file(${PROJECT_SOURCE_DIR}/libgenalyzer.pc.cmakein ${GENALYZER_PC} @ON install(FILES ${GENALYZER_PC} DESTINATION ${INSTALL_LIB_DIR}/pkgconfig) install(TARGETS genalyzer - ARCHIVE DESTINATION lib - LIBRARY DESTINATION "${INSTALL_LIB_DIR}" - RUNTIME DESTINATION bin - FRAMEWORK DESTINATION lib - PUBLIC_HEADER DESTINATION include) + ARCHIVE DESTINATION lib + LIBRARY DESTINATION "${INSTALL_LIB_DIR}" + RUNTIME DESTINATION bin + FRAMEWORK DESTINATION lib + PUBLIC_HEADER DESTINATION include) include(GNUInstallDirs) diff --git a/bindings/c/src/cgenalyzer.cpp b/bindings/c/src/cgenalyzer.cpp index b0c240a..9024dcf 100644 --- a/bindings/c/src/cgenalyzer.cpp +++ b/bindings/c/src/cgenalyzer.cpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #include "cgenalyzer.h" #include "cgenalyzer_private.h" @@ -5,50 +8,54 @@ using namespace util; namespace util { - static bool gn_null_terminate = true; - - size_t terminated_size(size_t string_size) - { - return string_size + (util::gn_null_terminate ? 1 : 0); - } - - void fill_string_buffer( - const char* src, // Pointer to source - size_t src_size, // Size of source; should not count null-terminator, if it exists - char* dst, // Pointer to destination - size_t dst_size // Size of destination - ) - { - if (nullptr == src) { - throw std::runtime_error("fill_string_buffer : source is NULL"); - } - if (nullptr == dst) { - throw std::runtime_error("fill_string_buffer : destination is NULL"); - } - if (dst_size < terminated_size(src_size)) { - throw std::runtime_error("fill_string_buffer : destination too small"); - } - for (size_t i = 0; i < src_size; ++i) { - dst[i] = src[i]; - } - if (gn_null_terminate) { - dst[src_size] = '\0'; - } - } - - std::string get_object_key_from_filename(const std::string& filename) - { - static const std::regex re {"(" + gn::manager::key_pattern + ")[.]json$", std::regex::icase}; - std::smatch matches; - if (std::regex_search(filename, matches, re)) { - if (1 == matches.size()) { - throw std::runtime_error("unable to derive object key from filename '" + filename + "'"); - } - return matches[1].str(); - } else { - throw std::runtime_error("invalid filename '" + filename + "'"); - } - } +static bool gn_null_terminate = true; + +size_t terminated_size(size_t string_size) { + return string_size + (util::gn_null_terminate ? 1 : 0); +} + +void fill_string_buffer( + const char *src, // Pointer to source + size_t src_size, // Size of source; should not count null-terminator, if it + // exists + char *dst, // Pointer to destination + size_t dst_size // Size of destination +) { + if (nullptr == src) { + throw std::runtime_error("fill_string_buffer : source is NULL"); + } + if (nullptr == dst) { + throw std::runtime_error( + "fill_string_buffer : destination is NULL"); + } + if (dst_size < terminated_size(src_size)) { + throw std::runtime_error( + "fill_string_buffer : destination too small"); + } + for (size_t i = 0; i < src_size; ++i) { + dst[i] = src[i]; + } + if (gn_null_terminate) { + dst[src_size] = '\0'; + } +} + +std::string get_object_key_from_filename(const std::string &filename) { + static const std::regex re{ + "(" + gn::manager::key_pattern + ")[.]json$", std::regex::icase + }; + std::smatch matches; + if (std::regex_search(filename, matches, re)) { + if (1 == matches.size()) { + throw std::runtime_error( + "unable to derive object key from filename '" + + filename + "'"); + } + return matches[1].str(); + } else { + throw std::runtime_error("invalid filename '" + filename + "'"); + } +} } // namespace util @@ -56,213 +63,202 @@ namespace util { /* API Utilities */ /**************************************************************************/ -int gn_analysis_results_key_sizes(size_t* key_sizes, size_t key_sizes_size, GnAnalysisType type) -{ - try { - util::check_pointer(key_sizes); - std::vector keys; - switch (gn::get_enum(type)) - { - case gn::AnalysisType::DNL : - keys = gn::dnl_analysis_ordered_keys(); - break; - case gn::AnalysisType::Histogram : - keys = gn::hist_analysis_ordered_keys(); - break; - case gn::AnalysisType::INL : - keys = gn::inl_analysis_ordered_keys(); - break; - case gn::AnalysisType::Waveform : - keys = gn::wf_analysis_ordered_keys(); - break; - default : - throw std::runtime_error("Invalid analysis type"); - } - if (keys.size() != key_sizes_size) { - throw std::runtime_error("Number of keys does not match output array size"); - } - for (size_t i = 0; i < key_sizes_size; ++i) { - key_sizes[i] = util::terminated_size(keys[i].size()); - } - return gn_success; - } catch (const std::exception& e) { - std::fill(key_sizes, key_sizes + key_sizes_size, 0); - return util::return_on_exception("gn_analysis_results_key_sizes : ", e.what()); - } -} - -int gn_analysis_results_size(size_t* size, GnAnalysisType type) -{ - try { - util::check_pointer(size); - switch (gn::get_enum(type)) - { - case gn::AnalysisType::DNL : - *size = gn::dnl_analysis_ordered_keys().size(); - break; - case gn::AnalysisType::Histogram : - *size = gn::hist_analysis_ordered_keys().size(); - break; - case gn::AnalysisType::INL : - *size = gn::inl_analysis_ordered_keys().size(); - break; - case gn::AnalysisType::Waveform : - *size = gn::wf_analysis_ordered_keys().size(); - break; - default : - throw std::runtime_error("Invalid analysis type"); - } - return gn_success; - } catch (const std::exception& e) { - *size = 0; - return util::return_on_exception("gn_analysis_results_size : ", e.what()); - } -} - -int gn_enum_value(int* value, const char* enumeration, const char* enumerator) -{ - try { - util::check_pointer(value); - *value = gn::enum_value(enumeration, enumerator); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_enum_value : ", e.what()); - } -} - -int gn_error_check(bool* error) -{ - try { - util::check_pointer(error); - *error = util::gn_error_log.check(); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_error_check : ", e.what()); - } -} - -int gn_error_clear() -{ - util::gn_error_log.clear(); - return gn_success; -} - -int gn_error_string(char* buf, size_t size) -{ - try { - std::string_view s = util::gn_error_log.get(); - util::fill_string_buffer(s.data(), s.size(), buf, size); - } catch (const std::exception&) { - return gn_failure; - } - return gn_success; -} - -int gn_set_string_termination(bool null_terminated) -{ - util::gn_null_terminate = null_terminated; - return gn_success; -} - -int gn_version_string(char* buf, size_t size) -{ - try { - std::string_view s = gn::version_string(); - util::fill_string_buffer(s.data(), s.size(), buf, size); - } catch (const std::exception& e) { - return util::return_on_exception("gn_version_string : ", e.what()); - } - return gn_success; +int gn_analysis_results_key_sizes(size_t *key_sizes, size_t key_sizes_size, + GnAnalysisType type) { + try { + util::check_pointer(key_sizes); + std::vector keys; + switch (gn::get_enum(type)) { + case gn::AnalysisType::DNL: + keys = gn::dnl_analysis_ordered_keys(); + break; + case gn::AnalysisType::Histogram: + keys = gn::hist_analysis_ordered_keys(); + break; + case gn::AnalysisType::INL: + keys = gn::inl_analysis_ordered_keys(); + break; + case gn::AnalysisType::Waveform: + keys = gn::wf_analysis_ordered_keys(); + break; + default: + throw std::runtime_error("Invalid analysis type"); + } + if (keys.size() != key_sizes_size) { + throw std::runtime_error( + "Number of keys does not match output array size"); + } + for (size_t i = 0; i < key_sizes_size; ++i) { + key_sizes[i] = util::terminated_size(keys[i].size()); + } + return gn_success; + } catch (const std::exception &e) { + std::fill(key_sizes, key_sizes + key_sizes_size, 0); + return util::return_on_exception( + "gn_analysis_results_key_sizes : ", e.what()); + } +} + +int gn_analysis_results_size(size_t *size, GnAnalysisType type) { + try { + util::check_pointer(size); + switch (gn::get_enum(type)) { + case gn::AnalysisType::DNL: + *size = gn::dnl_analysis_ordered_keys().size(); + break; + case gn::AnalysisType::Histogram: + *size = gn::hist_analysis_ordered_keys().size(); + break; + case gn::AnalysisType::INL: + *size = gn::inl_analysis_ordered_keys().size(); + break; + case gn::AnalysisType::Waveform: + *size = gn::wf_analysis_ordered_keys().size(); + break; + default: + throw std::runtime_error("Invalid analysis type"); + } + return gn_success; + } catch (const std::exception &e) { + *size = 0; + return util::return_on_exception("gn_analysis_results_size : ", + e.what()); + } +} + +int gn_enum_value(int *value, const char *enumeration, const char *enumerator) { + try { + util::check_pointer(value); + *value = gn::enum_value(enumeration, enumerator); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_enum_value : ", e.what()); + } +} + +int gn_error_check(bool *error) { + try { + util::check_pointer(error); + *error = util::gn_error_log.check(); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_error_check : ", e.what()); + } +} + +int gn_error_clear() { + util::gn_error_log.clear(); + return gn_success; +} + +int gn_error_string(char *buf, size_t size) { + try { + std::string_view s = util::gn_error_log.get(); + util::fill_string_buffer(s.data(), s.size(), buf, size); + } catch (const std::exception &) { + return gn_failure; + } + return gn_success; +} + +int gn_set_string_termination(bool null_terminated) { + util::gn_null_terminate = null_terminated; + return gn_success; +} + +int gn_version_string(char *buf, size_t size) { + try { + std::string_view s = gn::version_string(); + util::fill_string_buffer(s.data(), s.size(), buf, size); + } catch (const std::exception &e) { + return util::return_on_exception("gn_version_string : ", + e.what()); + } + return gn_success; } /**************************************************************************/ /* API Utility Helpers */ /**************************************************************************/ -int gn_error_string_size(size_t* size) -{ - try { - util::check_pointer(size); - *size = util::terminated_size(util::gn_error_log.size()); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_error_string_size : ", e.what()); - } +int gn_error_string_size(size_t *size) { + try { + util::check_pointer(size); + *size = util::terminated_size(util::gn_error_log.size()); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_error_string_size : ", + e.what()); + } } -int gn_version_string_size(size_t* size) -{ - try { - util::check_pointer(size); - *size = util::terminated_size(gn::version_string().size()); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_version_string_size : ", e.what()); - } +int gn_version_string_size(size_t *size) { + try { + util::check_pointer(size); + *size = util::terminated_size(gn::version_string().size()); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_version_string_size : ", + e.what()); + } } /**************************************************************************/ /* Array Operations */ /**************************************************************************/ -int gn_abs(double* out, size_t out_size, const double* in, size_t in_size) -{ - try { - gn::abs(in, in_size, out, out_size); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_abs : ", e.what()); - } -} - -int gn_angle(double* out, size_t out_size, const double* in, size_t in_size) -{ - try { - gn::angle(in, in_size, out, out_size); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_angle : ", e.what()); - } -} - -int gn_db(double* out, size_t out_size, const double* in, size_t in_size) -{ - try { - gn::db(in, in_size, out, out_size); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_db : ", e.what()); - } -} - -int gn_db10(double* out, size_t out_size, const double* in, size_t in_size) -{ - try { - gn::db10(in, in_size, out, out_size); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_db10 : ", e.what()); - } -} - -int gn_db20(double* out, size_t out_size, const double* in, size_t in_size) -{ - try { - gn::db20(in, in_size, out, out_size); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_db20 : ", e.what()); - } -} - -int gn_norm(double* out, size_t out_size, const double* in, size_t in_size) -{ - try { - gn::norm(in, in_size, out, out_size); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_norm : ", e.what()); - } +int gn_abs(double *out, size_t out_size, const double *in, size_t in_size) { + try { + gn::abs(in, in_size, out, out_size); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_abs : ", e.what()); + } +} + +int gn_angle(double *out, size_t out_size, const double *in, size_t in_size) { + try { + gn::angle(in, in_size, out, out_size); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_angle : ", e.what()); + } +} + +int gn_db(double *out, size_t out_size, const double *in, size_t in_size) { + try { + gn::db(in, in_size, out, out_size); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_db : ", e.what()); + } +} + +int gn_db10(double *out, size_t out_size, const double *in, size_t in_size) { + try { + gn::db10(in, in_size, out, out_size); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_db10 : ", e.what()); + } +} + +int gn_db20(double *out, size_t out_size, const double *in, size_t in_size) { + try { + gn::db20(in, in_size, out, out_size); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_db20 : ", e.what()); + } +} + +int gn_norm(double *out, size_t out_size, const double *in, size_t in_size) { + try { + gn::norm(in, in_size, out, out_size); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_norm : ", e.what()); + } } /**************************************************************************/ @@ -271,220 +267,228 @@ int gn_norm(double* out, size_t out_size, const double* in, size_t in_size) namespace { - template - int gn_hist(const char* suffix, uint64_t* hist, size_t hist_size, - const T* in, size_t in_size, int n, GnCodeFormat format, bool preserve) - { - try { - gn::CodeFormat f = gn::get_enum(format); - gn::hist(hist, hist_size, in, in_size, n, f, preserve); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_hist", suffix, " : ", e.what()); - } - } - - template - int gn_histx(const char* suffix, uint64_t* hist, size_t hist_size, - const T* in, size_t in_size, int64_t min, int64_t max, bool preserve) - { - try { - gn::histx(hist, hist_size, in, in_size, min, max, preserve); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_histx", suffix, " : ", e.what()); - } - } - -} // namespace anonymous - -int gn_code_axis(double* out, size_t size, int n, GnCodeFormat format) -{ - try { - gn::CodeFormat f = gn::get_enum(format); - gn::code_axis(out, size, n, f); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_code_axis : ", e.what()); - } -} - -int gn_code_axisx(double* out, size_t size, int64_t min, int64_t max) -{ - try { - gn::code_axisx(out, size, min, max); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_code_axisx : ", e.what()); - } -} - -int gn_dnl(double* dnl, size_t dnl_size, const uint64_t* hist, size_t hist_size, GnDnlSignal type) -{ - try { - gn::DnlSignal t = gn::get_enum(type); - gn::dnl(dnl, dnl_size, hist, hist_size, t); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_dnl : ", e.what()); - } -} - -int gn_dnl_analysis(char** rkeys, size_t rkeys_size, double* rvalues, size_t rvalues_size, - const double* dnl, size_t dnl_size) -{ - try { - util::check_pointer(rkeys); - util::check_pointer(rvalues); - const std::vector& keys = gn::dnl_analysis_ordered_keys(); - if (keys.size() != rkeys_size) { - throw std::runtime_error("Size of result key array is wrong"); - } - if (rvalues_size != rkeys_size) { - throw std::runtime_error("Size of result keys does not match size of result values"); - } - std::map results = gn::dnl_analysis(dnl, dnl_size); - for (size_t i = 0; i < keys.size(); ++i) { - const std::string& src = keys[i]; - char* dst = rkeys[i]; - size_t dst_size = util::terminated_size(src.size()); - util::fill_string_buffer(src.data(), src.size(), dst, dst_size); - rvalues[i] = results.at(src); - } - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_dnl_analysis : ", e.what()); - } -} - -int gn_hist16(uint64_t* hist, size_t hist_size, const int16_t* in, size_t in_size, - int n, GnCodeFormat format, bool preserve) -{ - return gn_hist("16", hist, hist_size, in, in_size, n, format, preserve); -} - -int gn_hist32(uint64_t* hist, size_t hist_size, const int32_t* in, size_t in_size, - int n, GnCodeFormat format, bool preserve) -{ - return gn_hist("32", hist, hist_size, in, in_size, n, format, preserve); -} - -int gn_hist64(uint64_t* hist, size_t hist_size, const int64_t* in, size_t in_size, - int n, GnCodeFormat format, bool preserve) -{ - return gn_hist("64", hist, hist_size, in, in_size, n, format, preserve); -} - -int gn_histx16(uint64_t* hist, size_t hist_size, const int16_t* in, size_t in_size, - int64_t min, int64_t max, bool preserve) -{ - return gn_histx("16", hist, hist_size, in, in_size, min, max, preserve); -} - -int gn_histx32(uint64_t* hist, size_t hist_size, const int32_t* in, size_t in_size, - int64_t min, int64_t max, bool preserve) -{ - return gn_histx("32", hist, hist_size, in, in_size, min, max, preserve); -} - -int gn_histx64(uint64_t* hist, size_t hist_size, const int64_t* in, size_t in_size, - int64_t min, int64_t max, bool preserve) -{ - return gn_histx("64", hist, hist_size, in, in_size, min, max, preserve); -} - -int gn_hist_analysis(char** rkeys, size_t rkeys_size, double* rvalues, size_t rvalues_size, - const uint64_t* hist, size_t hist_size) -{ - try { - util::check_pointer(rkeys); - util::check_pointer(rvalues); - const std::vector& keys = gn::hist_analysis_ordered_keys(); - if (keys.size() != rkeys_size) { - throw std::runtime_error("Size of result key array is wrong"); - } - if (rvalues_size != rkeys_size) { - throw std::runtime_error("Size of result keys does not match size of result values"); - } - std::map results = gn::hist_analysis(hist, hist_size); - for (size_t i = 0; i < keys.size(); ++i) { - const std::string& src = keys[i]; - char* dst = rkeys[i]; - size_t dst_size = util::terminated_size(src.size()); - util::fill_string_buffer(src.data(), src.size(), dst, dst_size); - rvalues[i] = results.at(src); - } - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_hist_analysis : ", e.what()); - } -} - -int gn_inl(double* inl, size_t inl_size, const double* dnl, size_t dnl_size, GnInlLineFit fit) -{ - try { - gn::InlLineFit f = gn::get_enum(fit); - gn::inl(inl, inl_size, dnl, dnl_size, f); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_inl : ", e.what()); - } -} - -int gn_inl_analysis(char** rkeys, size_t rkeys_size, double* rvalues, size_t rvalues_size, - const double* inl, size_t inl_size) -{ - try { - util::check_pointer(rkeys); - util::check_pointer(rvalues); - const std::vector& keys = gn::inl_analysis_ordered_keys(); - if (keys.size() != rkeys_size) { - throw std::runtime_error("Size of result key array is wrong"); - } - if (rvalues_size != rkeys_size) { - throw std::runtime_error("Size of result keys does not match size of result values"); - } - std::map results = gn::inl_analysis(inl, inl_size); - for (size_t i = 0; i < keys.size(); ++i) { - const std::string& src = keys[i]; - char* dst = rkeys[i]; - size_t dst_size = util::terminated_size(src.size()); - util::fill_string_buffer(src.data(), src.size(), dst, dst_size); - rvalues[i] = results.at(src); - } - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_inl_analysis : ", e.what()); - } +template +int gn_hist(const char *suffix, uint64_t *hist, size_t hist_size, const T *in, + size_t in_size, int n, GnCodeFormat format, bool preserve) { + try { + gn::CodeFormat f = gn::get_enum(format); + gn::hist(hist, hist_size, in, in_size, n, f, preserve); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_hist", suffix, " : ", + e.what()); + } +} + +template +int gn_histx(const char *suffix, uint64_t *hist, size_t hist_size, const T *in, + size_t in_size, int64_t min, int64_t max, bool preserve) { + try { + gn::histx(hist, hist_size, in, in_size, min, max, preserve); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_histx", suffix, " : ", + e.what()); + } +} + +} // namespace + +int gn_code_axis(double *out, size_t size, int n, GnCodeFormat format) { + try { + gn::CodeFormat f = gn::get_enum(format); + gn::code_axis(out, size, n, f); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_code_axis : ", e.what()); + } +} + +int gn_code_axisx(double *out, size_t size, int64_t min, int64_t max) { + try { + gn::code_axisx(out, size, min, max); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_code_axisx : ", e.what()); + } +} + +int gn_dnl(double *dnl, size_t dnl_size, const uint64_t *hist, size_t hist_size, + GnDnlSignal type) { + try { + gn::DnlSignal t = gn::get_enum(type); + gn::dnl(dnl, dnl_size, hist, hist_size, t); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_dnl : ", e.what()); + } +} + +int gn_dnl_analysis(char **rkeys, size_t rkeys_size, double *rvalues, + size_t rvalues_size, const double *dnl, size_t dnl_size) { + try { + util::check_pointer(rkeys); + util::check_pointer(rvalues); + const std::vector &keys = + gn::dnl_analysis_ordered_keys(); + if (keys.size() != rkeys_size) { + throw std::runtime_error( + "Size of result key array is wrong"); + } + if (rvalues_size != rkeys_size) { + throw std::runtime_error( + "Size of result keys does not match size of result values"); + } + std::map results = + gn::dnl_analysis(dnl, dnl_size); + for (size_t i = 0; i < keys.size(); ++i) { + const std::string &src = keys[i]; + char *dst = rkeys[i]; + size_t dst_size = util::terminated_size(src.size()); + util::fill_string_buffer(src.data(), src.size(), dst, + dst_size); + rvalues[i] = results.at(src); + } + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_dnl_analysis : ", + e.what()); + } +} + +int gn_hist16(uint64_t *hist, size_t hist_size, const int16_t *in, + size_t in_size, int n, GnCodeFormat format, bool preserve) { + return gn_hist("16", hist, hist_size, in, in_size, n, format, preserve); +} + +int gn_hist32(uint64_t *hist, size_t hist_size, const int32_t *in, + size_t in_size, int n, GnCodeFormat format, bool preserve) { + return gn_hist("32", hist, hist_size, in, in_size, n, format, preserve); +} + +int gn_hist64(uint64_t *hist, size_t hist_size, const int64_t *in, + size_t in_size, int n, GnCodeFormat format, bool preserve) { + return gn_hist("64", hist, hist_size, in, in_size, n, format, preserve); +} + +int gn_histx16(uint64_t *hist, size_t hist_size, const int16_t *in, + size_t in_size, int64_t min, int64_t max, bool preserve) { + return gn_histx("16", hist, hist_size, in, in_size, min, max, preserve); +} + +int gn_histx32(uint64_t *hist, size_t hist_size, const int32_t *in, + size_t in_size, int64_t min, int64_t max, bool preserve) { + return gn_histx("32", hist, hist_size, in, in_size, min, max, preserve); +} + +int gn_histx64(uint64_t *hist, size_t hist_size, const int64_t *in, + size_t in_size, int64_t min, int64_t max, bool preserve) { + return gn_histx("64", hist, hist_size, in, in_size, min, max, preserve); +} + +int gn_hist_analysis(char **rkeys, size_t rkeys_size, double *rvalues, + size_t rvalues_size, const uint64_t *hist, + size_t hist_size) { + try { + util::check_pointer(rkeys); + util::check_pointer(rvalues); + const std::vector &keys = + gn::hist_analysis_ordered_keys(); + if (keys.size() != rkeys_size) { + throw std::runtime_error( + "Size of result key array is wrong"); + } + if (rvalues_size != rkeys_size) { + throw std::runtime_error( + "Size of result keys does not match size of result values"); + } + std::map results = + gn::hist_analysis(hist, hist_size); + for (size_t i = 0; i < keys.size(); ++i) { + const std::string &src = keys[i]; + char *dst = rkeys[i]; + size_t dst_size = util::terminated_size(src.size()); + util::fill_string_buffer(src.data(), src.size(), dst, + dst_size); + rvalues[i] = results.at(src); + } + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_hist_analysis : ", + e.what()); + } +} + +int gn_inl(double *inl, size_t inl_size, const double *dnl, size_t dnl_size, + GnInlLineFit fit) { + try { + gn::InlLineFit f = gn::get_enum(fit); + gn::inl(inl, inl_size, dnl, dnl_size, f); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_inl : ", e.what()); + } +} + +int gn_inl_analysis(char **rkeys, size_t rkeys_size, double *rvalues, + size_t rvalues_size, const double *inl, size_t inl_size) { + try { + util::check_pointer(rkeys); + util::check_pointer(rvalues); + const std::vector &keys = + gn::inl_analysis_ordered_keys(); + if (keys.size() != rkeys_size) { + throw std::runtime_error( + "Size of result key array is wrong"); + } + if (rvalues_size != rkeys_size) { + throw std::runtime_error( + "Size of result keys does not match size of result values"); + } + std::map results = + gn::inl_analysis(inl, inl_size); + for (size_t i = 0; i < keys.size(); ++i) { + const std::string &src = keys[i]; + char *dst = rkeys[i]; + size_t dst_size = util::terminated_size(src.size()); + util::fill_string_buffer(src.data(), src.size(), dst, + dst_size); + rvalues[i] = results.at(src); + } + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_inl_analysis : ", + e.what()); + } } /**************************************************************************/ /* Code Density Helpers */ /**************************************************************************/ -int gn_code_density_size(size_t* size, int n, GnCodeFormat format) -{ - try { - util::check_pointer(size); - gn::CodeFormat f = gn::get_enum(format); - *size = gn::code_density_size(n, f); - return gn_success; - } catch (const std::exception& e) { - *size = 0; - return util::return_on_exception("gn_code_density_size : ", e.what()); - } -} - -int gn_code_densityx_size(size_t* size, int64_t min, int64_t max) -{ - try { - util::check_pointer(size); - *size = gn::code_densityx_size(min, max); - return gn_success; - } catch (const std::exception& e) { - *size = 0; - return util::return_on_exception("gn_code_densityx_size : ", e.what()); - } +int gn_code_density_size(size_t *size, int n, GnCodeFormat format) { + try { + util::check_pointer(size); + gn::CodeFormat f = gn::get_enum(format); + *size = gn::code_density_size(n, f); + return gn_success; + } catch (const std::exception &e) { + *size = 0; + return util::return_on_exception("gn_code_density_size : ", + e.what()); + } +} + +int gn_code_densityx_size(size_t *size, int64_t min, int64_t max) { + try { + util::check_pointer(size); + *size = gn::code_densityx_size(min, max); + return gn_success; + } catch (const std::exception &e) { + *size = 0; + return util::return_on_exception("gn_code_densityx_size : ", + e.what()); + } } /**************************************************************************/ @@ -493,630 +497,659 @@ int gn_code_densityx_size(size_t* size, int64_t min, int64_t max) namespace { - using fa_ptr = std::shared_ptr; - - fa_ptr get_fa_object(const std::string& obj_key) - { - gn::object::pointer pobj = gn::manager::get_object(obj_key); - const gn::ObjectType obj_type = gn::ObjectType::FourierAnalysis; - if (obj_type != pobj->object_type()) { - throw std::runtime_error("object '" + obj_key + "' is not of type " - + gn::object_type_map.at(static_cast(obj_type))); - } - return std::static_pointer_cast(pobj); - } - - fa_ptr get_fa_object_or_load_from_file(std::string cfg_id) - { - if (gn::manager::contains(cfg_id)) { - return get_fa_object(cfg_id); - } else { - return gn::fourier_analysis::load(cfg_id); - } - } - - size_t get_fa_result_key_index(const char** rkeys, size_t rkeys_size, const char* rkey) - { - size_t i = 0; - for (; i < rkeys_size; ++i) { - if (0 == strcmp(rkeys[i], rkey)) { - break; - } - } - if (rkeys_size == i) { - throw std::runtime_error("Result key '" + std::string(rkey) + "' not found"); - } - return i; - } - - std::string get_fa_result_string(const char** rkeys, size_t rkeys_size, - const double* rvalues, size_t rvalues_size, const char* rkey) - { - if (rkeys_size != rvalues_size) { - throw std::runtime_error("Size of result keys does not match size of result values"); - } - if (gn::fa_result_map.contains(rkey, true)) { - gn::FAResult renum = static_cast(gn::fa_result_map.at(rkey)); - if (gn::FAResult::CarrierIndex == renum || - gn::FAResult::MaxSpurIndex == renum) { - // Caller requests the Carrier or MaxSpur tone key. - size_t key_index = get_fa_result_key_index(rkeys, rkeys_size, rkey); - size_t order_index = static_cast(rvalues[key_index]); - int order_index_int = static_cast(gn::FAToneResult::OrderIndex); - std::string search_str = ":" + gn::fa_tone_result_map.at(order_index_int); - const char* search_cstr = search_str.c_str(); - size_t i = 0; - for (; i < rvalues_size; ++i) { - if (strstr(rkeys[i], search_cstr)) { - if (rvalues[i] == order_index) { - break; - } - } - } - if (rvalues_size == i) { - return "Not Found"; - } else { - return gn::fourier_analysis::split_key(rkeys[i]).first; - } - } - } else { - // In the future, there could be a string associated with a tone result. - } - throw std::runtime_error("no string associated with result key '" + std::string(rkey) + "'"); - } - - int get_fa_single_result( - const gn::fourier_analysis_results& results, const char* rkey, double* rvalue) - { - *rvalue = 0.0; - std::pair keys = gn::fourier_analysis::split_key(rkey); - if (!keys.first.empty()) { - if (keys.second.empty()) { - if (gn::fa_result_map.contains(keys.first)) { - int i = gn::fa_result_map.at(keys.first); - *rvalue = results.get(static_cast(i)); - return gn_success; - } - } else { - if (results.contains_tone(keys.first)) { - const gn::fa_tone_results& tres = results.get_tone(keys.first); - if (gn::fa_tone_result_map.at(keys.second)) { - int i = gn::fa_tone_result_map.at(keys.second); - *rvalue = tres.get(static_cast(i)); - return gn_success; - } - } - } - } - return gn_failure; - } - -} // namespace anonymous - -int gn_fft_analysis(char** rkeys, size_t rkeys_size, double* rvalues, size_t rvalues_size, - const char* cfg_id, const double* in, size_t in_size, size_t nfft, GnFreqAxisType axis_type) -{ - try { - if (rkeys_size != rvalues_size) { - throw std::runtime_error("Size of result keys does not match size of result values"); - } - fa_ptr obj = get_fa_object_or_load_from_file(cfg_id); - gn::FreqAxisType at = gn::get_enum(axis_type); - gn::fourier_analysis_results results = obj->analyze(in, in_size, nfft, at); - // The rest of this function flattens results into a key-array and value-array pair - size_t i = 0; // index for rkeys, rvalues - const std::map& rmap = results.results; - for (int j = 0; j < static_cast(gn::FAResult::__SIZE__); ++j) { - const std::string& src = gn::fa_result_map.at(j); - char* dst = rkeys[i]; - size_t dst_size = util::terminated_size(src.size()); - util::fill_string_buffer(src.data(), src.size(), dst, dst_size); - rvalues[i] = rmap.at(static_cast(j)); - i += 1; - } - for (const std::string& tkey : results.tone_keys) { - const gn::fa_tone_results& tone_results = results.get_tone(tkey); - const std::map& trmap = tone_results.results; - for (int j = 0; j < static_cast(gn::FAToneResult::__SIZE__); ++j) { - std::string src = gn::fourier_analysis::flat_tone_key(tkey, j); - char* dst = rkeys[i]; - size_t dst_size = util::terminated_size(src.size()); - util::fill_string_buffer(src.data(), src.size(), dst, dst_size); - rvalues[i] = trmap.at(static_cast(j)); - i += 1; - } - } - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_execute : ", e.what()); - } -} - -int gn_fft_analysis_select(double* rvalues, size_t rvalues_size, - const char* cfg_id, const char** rkeys, size_t rkeys_size, - const double* in, size_t in_size, size_t nfft, GnFreqAxisType axis_type) -{ - try { - if (rkeys_size != rvalues_size) { - throw std::runtime_error("Size of result keys does not match size of result values"); - } - fa_ptr obj = get_fa_object_or_load_from_file(cfg_id); - gn::FreqAxisType at = gn::get_enum(axis_type); - gn::fourier_analysis_results results = obj->analyze(in, in_size, nfft, at); - std::string missing_keys {}; - for (size_t i = 0; i < rkeys_size; ++i) { - int error = get_fa_single_result(results, rkeys[i], &rvalues[i]); - if (error) { - if (!missing_keys.empty()) { - missing_keys += ", "; - } - missing_keys.append("'" + std::string(rkeys[i]) + "'"); - } - } - if (!missing_keys.empty()) { - throw std::runtime_error("Keys not found: " + missing_keys); - } - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_execute2 : ", e.what()); - } -} - -int gn_fft_analysis_single(double* rvalue, - const char* cfg_id, const char* rkey, - const double* in, size_t in_size, size_t nfft, GnFreqAxisType axis_type) -{ - try { - fa_ptr obj = get_fa_object_or_load_from_file(cfg_id); - gn::FreqAxisType at = gn::get_enum(axis_type); - gn::fourier_analysis_results results = obj->analyze(in, in_size, nfft, at); - int error = get_fa_single_result(results, rkey, rvalue); - if (error) { - throw std::runtime_error("Key '" + std::string(rkey) + "' not found"); - } - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_execute1 : ", e.what()); - } +using fa_ptr = std::shared_ptr; + +fa_ptr get_fa_object(const std::string &obj_key) { + gn::object::pointer pobj = gn::manager::get_object(obj_key); + const gn::ObjectType obj_type = gn::ObjectType::FourierAnalysis; + if (obj_type != pobj->object_type()) { + throw std::runtime_error( + "object '" + obj_key + "' is not of type " + + gn::object_type_map.at(static_cast(obj_type))); + } + return std::static_pointer_cast(pobj); +} + +fa_ptr get_fa_object_or_load_from_file(std::string cfg_id) { + if (gn::manager::contains(cfg_id)) { + return get_fa_object(cfg_id); + } else { + return gn::fourier_analysis::load(cfg_id); + } +} + +size_t get_fa_result_key_index(const char **rkeys, size_t rkeys_size, + const char *rkey) { + size_t i = 0; + for (; i < rkeys_size; ++i) { + if (0 == strcmp(rkeys[i], rkey)) { + break; + } + } + if (rkeys_size == i) { + throw std::runtime_error("Result key '" + std::string(rkey) + + "' not found"); + } + return i; +} + +std::string get_fa_result_string(const char **rkeys, size_t rkeys_size, + const double *rvalues, size_t rvalues_size, + const char *rkey) { + if (rkeys_size != rvalues_size) { + throw std::runtime_error( + "Size of result keys does not match size of result values"); + } + if (gn::fa_result_map.contains(rkey, true)) { + gn::FAResult renum = + static_cast(gn::fa_result_map.at(rkey)); + if (gn::FAResult::CarrierIndex == renum || + gn::FAResult::MaxSpurIndex == renum) { + // Caller requests the Carrier or MaxSpur tone key. + size_t key_index = get_fa_result_key_index( + rkeys, rkeys_size, rkey); + size_t order_index = + static_cast(rvalues[key_index]); + int order_index_int = + static_cast(gn::FAToneResult::OrderIndex); + std::string search_str = + ":" + + gn::fa_tone_result_map.at(order_index_int); + const char *search_cstr = search_str.c_str(); + size_t i = 0; + for (; i < rvalues_size; ++i) { + if (strstr(rkeys[i], search_cstr)) { + if (rvalues[i] == order_index) { + break; + } + } + } + if (rvalues_size == i) { + return "Not Found"; + } else { + return gn::fourier_analysis::split_key(rkeys[i]) + .first; + } + } + } else { + // In the future, there could be a string associated with a tone result. + } + throw std::runtime_error("no string associated with result key '" + + std::string(rkey) + "'"); +} + +int get_fa_single_result(const gn::fourier_analysis_results &results, + const char *rkey, double *rvalue) { + *rvalue = 0.0; + std::pair keys = + gn::fourier_analysis::split_key(rkey); + if (!keys.first.empty()) { + if (keys.second.empty()) { + if (gn::fa_result_map.contains(keys.first)) { + int i = gn::fa_result_map.at(keys.first); + *rvalue = results.get( + static_cast(i)); + return gn_success; + } + } else { + if (results.contains_tone(keys.first)) { + const gn::fa_tone_results &tres = + results.get_tone(keys.first); + if (gn::fa_tone_result_map.at(keys.second)) { + int i = gn::fa_tone_result_map.at( + keys.second); + *rvalue = tres.get( + static_cast( + i)); + return gn_success; + } + } + } + } + return gn_failure; +} + +} // namespace + +int gn_fft_analysis(char **rkeys, size_t rkeys_size, double *rvalues, + size_t rvalues_size, const char *cfg_id, const double *in, + size_t in_size, size_t nfft, GnFreqAxisType axis_type) { + try { + if (rkeys_size != rvalues_size) { + throw std::runtime_error( + "Size of result keys does not match size of result values"); + } + fa_ptr obj = get_fa_object_or_load_from_file(cfg_id); + gn::FreqAxisType at = gn::get_enum(axis_type); + gn::fourier_analysis_results results = + obj->analyze(in, in_size, nfft, at); + // The rest of this function flattens results into a key-array and + // value-array pair + size_t i = 0; // index for rkeys, rvalues + const std::map &rmap = results.results; + for (int j = 0; j < static_cast(gn::FAResult::__SIZE__); + ++j) { + const std::string &src = gn::fa_result_map.at(j); + char *dst = rkeys[i]; + size_t dst_size = util::terminated_size(src.size()); + util::fill_string_buffer(src.data(), src.size(), dst, + dst_size); + rvalues[i] = rmap.at(static_cast(j)); + i += 1; + } + for (const std::string &tkey : results.tone_keys) { + const gn::fa_tone_results &tone_results = + results.get_tone(tkey); + const std::map &trmap = + tone_results.results; + for (int j = 0; + j < static_cast(gn::FAToneResult::__SIZE__); + ++j) { + std::string src = + gn::fourier_analysis::flat_tone_key( + tkey, j); + char *dst = rkeys[i]; + size_t dst_size = + util::terminated_size(src.size()); + util::fill_string_buffer(src.data(), src.size(), + dst, dst_size); + rvalues[i] = trmap.at( + static_cast(j)); + i += 1; + } + } + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_execute : ", e.what()); + } +} + +int gn_fft_analysis_select(double *rvalues, size_t rvalues_size, + const char *cfg_id, const char **rkeys, + size_t rkeys_size, const double *in, size_t in_size, + size_t nfft, GnFreqAxisType axis_type) { + try { + if (rkeys_size != rvalues_size) { + throw std::runtime_error( + "Size of result keys does not match size of result values"); + } + fa_ptr obj = get_fa_object_or_load_from_file(cfg_id); + gn::FreqAxisType at = gn::get_enum(axis_type); + gn::fourier_analysis_results results = + obj->analyze(in, in_size, nfft, at); + std::string missing_keys{}; + for (size_t i = 0; i < rkeys_size; ++i) { + int error = get_fa_single_result(results, rkeys[i], + &rvalues[i]); + if (error) { + if (!missing_keys.empty()) { + missing_keys += ", "; + } + missing_keys.append( + "'" + std::string(rkeys[i]) + "'"); + } + } + if (!missing_keys.empty()) { + throw std::runtime_error("Keys not found: " + + missing_keys); + } + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_execute2 : ", e.what()); + } +} + +int gn_fft_analysis_single(double *rvalue, const char *cfg_id, const char *rkey, + const double *in, size_t in_size, size_t nfft, + GnFreqAxisType axis_type) { + try { + fa_ptr obj = get_fa_object_or_load_from_file(cfg_id); + gn::FreqAxisType at = gn::get_enum(axis_type); + gn::fourier_analysis_results results = + obj->analyze(in, in_size, nfft, at); + int error = get_fa_single_result(results, rkey, rvalue); + if (error) { + throw std::runtime_error("Key '" + std::string(rkey) + + "' not found"); + } + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_execute1 : ", e.what()); + } } /**************************************************************************/ /* Fourier Analysis Configuration */ /**************************************************************************/ -int gn_fa_analysis_band(const char* obj_key, double center, double width) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - std::string center_s = gn::to_string(center, gn::FPFormat::Eng); - std::string width_s = gn::to_string(width, gn::FPFormat::Eng); - obj->set_analysis_band(center_s, width_s); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_analysis_band : ", e.what()); - } -} - -int gn_fa_analysis_band_e(const char* obj_key, const char* center, const char* width) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - obj->set_analysis_band(center, width); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_analysis_band_e : ", e.what()); - } -} - -int gn_fa_clk(const char* obj_key, const int* clk, size_t clk_size, bool as_noise) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - std::set clk2 (clk, clk + clk_size); - obj->set_clk(clk2); - obj->clk_as_noise = as_noise; - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_clk : ", e.what()); - } -} - -int gn_fa_conv_offset(const char* obj_key, bool enable) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - obj->en_conv_offset = enable; - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_conv_offset : ", e.what()); - } -} - -int gn_fa_create(const char* obj_key) -{ - try { - gn::manager::add_object(obj_key, gn::fourier_analysis::create(), false); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_create : ", e.what()); - } -} - -int gn_fa_dc(const char* obj_key, bool as_dist) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - obj->dc_as_dist = as_dist; - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_dc : ", e.what()); - } -} - -int gn_fa_fdata(const char* obj_key, double f) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - std::string f_s = gn::to_string(f, gn::FPFormat::Eng); - obj->set_fdata(f_s); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_fdata : ", e.what()); - } -} - -int gn_fa_fdata_e(const char* obj_key, const char* f) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - obj->set_fdata(f); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_fdata_e : ", e.what()); - } -} - -int gn_fa_fixed_tone( - const char* obj_key, const char* comp_key, GnFACompTag tag, double freq, int ssb) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - gn::FACompTag t = gn::get_enum(tag); - std::string freq_s = gn::to_string(freq, gn::FPFormat::Eng); - obj->add_fixed_tone(comp_key, t, freq_s, ssb); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_fixed_tone : ", e.what()); - } -} - -int gn_fa_fixed_tone_e( - const char* obj_key, const char* comp_key, GnFACompTag tag, const char* freq, int ssb) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - gn::FACompTag t = gn::get_enum(tag); - obj->add_fixed_tone(comp_key, t, freq, ssb); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_fixed_tone_e : ", e.what()); - } -} - -int gn_fa_fsample(const char* obj_key, double f) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - std::string f_s = gn::to_string(f, gn::FPFormat::Eng); - obj->set_fsample(f_s); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_fsample : ", e.what()); - } -} - -int gn_fa_fsample_e(const char* obj_key, const char* f) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - obj->set_fsample(f); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_fsample_e : ", e.what()); - } -} - -int gn_fa_fshift(const char* obj_key, double f) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - std::string f_s = gn::to_string(f, gn::FPFormat::Eng); - obj->set_fshift(f_s); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_fshift : ", e.what()); - } -} - -int gn_fa_fshift_e(const char* obj_key, const char* f) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - obj->set_fshift(f); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_fshift_e : ", e.what()); - } -} - -int gn_fa_fund_images(const char* obj_key, bool enable) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - obj->en_fund_images = enable; - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_fund_images : ", e.what()); - } -} - -int gn_fa_hd(const char* obj_key, int n) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - obj->set_hd(n); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_hd : ", e.what()); - } -} - -int gn_fa_ilv(const char* obj_key, const int* ilv, size_t ilv_size, bool as_noise) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - std::set ilv2 (ilv, ilv + ilv_size); - obj->set_ilv(ilv2); - obj->ilv_as_noise = as_noise; - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_ilv : ", e.what()); - } -} - -int gn_fa_imd(const char* obj_key, int n) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - obj->set_imd(n); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_imd : ", e.what()); - } -} - -int gn_fa_load(char* buf, size_t size, const char* filename, const char* obj_key) -{ - try { - std::string key (obj_key); - if (key.empty()) { - key = util::get_object_key_from_filename(filename); - } - gn::manager::add_object(key, gn::fourier_analysis::load(filename), true); - util::fill_string_buffer(key.data(), key.size(), buf, size); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_load : ", e.what()); - } -} - -int gn_fa_max_tone( - const char* obj_key, - const char* comp_key, - GnFACompTag tag, - int ssb) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - gn::FACompTag t = gn::get_enum(tag); - obj->add_max_tone(comp_key, t, "0.0", "fdata", ssb); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_max_tone : ", e.what()); - } -} - -int gn_fa_preview(char* buf, size_t size, const char* cfg_id, bool cplx) -{ - try { - fa_ptr obj = get_fa_object_or_load_from_file(cfg_id); - std::string s = obj->preview(cplx); - util::fill_string_buffer(s.data(), s.size(), buf, size); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_preview : ", e.what()); - } -} - -int gn_fa_quad_errors(const char* obj_key, bool enable) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - obj->en_quad_errors = enable; - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_quad_errors : ", e.what()); - } -} - -int gn_fa_remove_comp(const char* obj_key, const char* comp_key) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - obj->remove_comp(comp_key); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_remove_comp : ", e.what()); - } -} - -int gn_fa_reset(const char* obj_key) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - obj->reset(); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_reset : ", e.what()); - } -} - -int gn_fa_ssb(const char* obj_key, GnFASsb group, int ssb) -{ - try { - gn::FASsb g = gn::get_enum(group); - fa_ptr obj = get_fa_object(obj_key); - obj->set_ssb(g, ssb); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_ssb_dc : ", e.what()); - } -} - -int gn_fa_var(const char* obj_key, const char* name, double value) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - obj->set_var(name, value); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_var : ", e.what()); - } -} - -int gn_fa_wo(const char* obj_key, int n) -{ - try { - fa_ptr obj = get_fa_object(obj_key); - obj->set_wo(n); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_wo : ", e.what()); - } +int gn_fa_analysis_band(const char *obj_key, double center, double width) { + try { + fa_ptr obj = get_fa_object(obj_key); + std::string center_s = gn::to_string(center, gn::FPFormat::Eng); + std::string width_s = gn::to_string(width, gn::FPFormat::Eng); + obj->set_analysis_band(center_s, width_s); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_analysis_band : ", + e.what()); + } +} + +int gn_fa_analysis_band_e(const char *obj_key, const char *center, + const char *width) { + try { + fa_ptr obj = get_fa_object(obj_key); + obj->set_analysis_band(center, width); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_analysis_band_e : ", + e.what()); + } +} + +int gn_fa_clk(const char *obj_key, const int *clk, size_t clk_size, + bool as_noise) { + try { + fa_ptr obj = get_fa_object(obj_key); + std::set clk2(clk, clk + clk_size); + obj->set_clk(clk2); + obj->clk_as_noise = as_noise; + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_clk : ", e.what()); + } +} + +int gn_fa_conv_offset(const char *obj_key, bool enable) { + try { + fa_ptr obj = get_fa_object(obj_key); + obj->en_conv_offset = enable; + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_conv_offset : ", + e.what()); + } +} + +int gn_fa_create(const char *obj_key) { + try { + gn::manager::add_object(obj_key, gn::fourier_analysis::create(), + false); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_create : ", e.what()); + } +} + +int gn_fa_dc(const char *obj_key, bool as_dist) { + try { + fa_ptr obj = get_fa_object(obj_key); + obj->dc_as_dist = as_dist; + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_dc : ", e.what()); + } +} + +int gn_fa_fdata(const char *obj_key, double f) { + try { + fa_ptr obj = get_fa_object(obj_key); + std::string f_s = gn::to_string(f, gn::FPFormat::Eng); + obj->set_fdata(f_s); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_fdata : ", e.what()); + } +} + +int gn_fa_fdata_e(const char *obj_key, const char *f) { + try { + fa_ptr obj = get_fa_object(obj_key); + obj->set_fdata(f); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_fdata_e : ", e.what()); + } +} + +int gn_fa_fixed_tone(const char *obj_key, const char *comp_key, GnFACompTag tag, + double freq, int ssb) { + try { + fa_ptr obj = get_fa_object(obj_key); + gn::FACompTag t = gn::get_enum(tag); + std::string freq_s = gn::to_string(freq, gn::FPFormat::Eng); + obj->add_fixed_tone(comp_key, t, freq_s, ssb); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_fixed_tone : ", + e.what()); + } +} + +int gn_fa_fixed_tone_e(const char *obj_key, const char *comp_key, + GnFACompTag tag, const char *freq, int ssb) { + try { + fa_ptr obj = get_fa_object(obj_key); + gn::FACompTag t = gn::get_enum(tag); + obj->add_fixed_tone(comp_key, t, freq, ssb); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_fixed_tone_e : ", + e.what()); + } +} + +int gn_fa_fsample(const char *obj_key, double f) { + try { + fa_ptr obj = get_fa_object(obj_key); + std::string f_s = gn::to_string(f, gn::FPFormat::Eng); + obj->set_fsample(f_s); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_fsample : ", e.what()); + } +} + +int gn_fa_fsample_e(const char *obj_key, const char *f) { + try { + fa_ptr obj = get_fa_object(obj_key); + obj->set_fsample(f); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_fsample_e : ", + e.what()); + } +} + +int gn_fa_fshift(const char *obj_key, double f) { + try { + fa_ptr obj = get_fa_object(obj_key); + std::string f_s = gn::to_string(f, gn::FPFormat::Eng); + obj->set_fshift(f_s); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_fshift : ", e.what()); + } +} + +int gn_fa_fshift_e(const char *obj_key, const char *f) { + try { + fa_ptr obj = get_fa_object(obj_key); + obj->set_fshift(f); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_fshift_e : ", e.what()); + } +} + +int gn_fa_fund_images(const char *obj_key, bool enable) { + try { + fa_ptr obj = get_fa_object(obj_key); + obj->en_fund_images = enable; + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_fund_images : ", + e.what()); + } +} + +int gn_fa_hd(const char *obj_key, int n) { + try { + fa_ptr obj = get_fa_object(obj_key); + obj->set_hd(n); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_hd : ", e.what()); + } +} + +int gn_fa_ilv(const char *obj_key, const int *ilv, size_t ilv_size, + bool as_noise) { + try { + fa_ptr obj = get_fa_object(obj_key); + std::set ilv2(ilv, ilv + ilv_size); + obj->set_ilv(ilv2); + obj->ilv_as_noise = as_noise; + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_ilv : ", e.what()); + } +} + +int gn_fa_imd(const char *obj_key, int n) { + try { + fa_ptr obj = get_fa_object(obj_key); + obj->set_imd(n); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_imd : ", e.what()); + } +} + +int gn_fa_load(char *buf, size_t size, const char *filename, + const char *obj_key) { + try { + std::string key(obj_key); + if (key.empty()) { + key = util::get_object_key_from_filename(filename); + } + gn::manager::add_object( + key, gn::fourier_analysis::load(filename), true); + util::fill_string_buffer(key.data(), key.size(), buf, size); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_load : ", e.what()); + } +} + +int gn_fa_max_tone(const char *obj_key, const char *comp_key, GnFACompTag tag, + int ssb) { + try { + fa_ptr obj = get_fa_object(obj_key); + gn::FACompTag t = gn::get_enum(tag); + obj->add_max_tone(comp_key, t, "0.0", "fdata", ssb); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_max_tone : ", e.what()); + } +} + +int gn_fa_preview(char *buf, size_t size, const char *cfg_id, bool cplx) { + try { + fa_ptr obj = get_fa_object_or_load_from_file(cfg_id); + std::string s = obj->preview(cplx); + util::fill_string_buffer(s.data(), s.size(), buf, size); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_preview : ", e.what()); + } +} + +int gn_fa_quad_errors(const char *obj_key, bool enable) { + try { + fa_ptr obj = get_fa_object(obj_key); + obj->en_quad_errors = enable; + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_quad_errors : ", + e.what()); + } +} + +int gn_fa_remove_comp(const char *obj_key, const char *comp_key) { + try { + fa_ptr obj = get_fa_object(obj_key); + obj->remove_comp(comp_key); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_remove_comp : ", + e.what()); + } +} + +int gn_fa_reset(const char *obj_key) { + try { + fa_ptr obj = get_fa_object(obj_key); + obj->reset(); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_reset : ", e.what()); + } +} + +int gn_fa_ssb(const char *obj_key, GnFASsb group, int ssb) { + try { + gn::FASsb g = gn::get_enum(group); + fa_ptr obj = get_fa_object(obj_key); + obj->set_ssb(g, ssb); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_ssb_dc : ", e.what()); + } +} + +int gn_fa_var(const char *obj_key, const char *name, double value) { + try { + fa_ptr obj = get_fa_object(obj_key); + obj->set_var(name, value); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_var : ", e.what()); + } +} + +int gn_fa_wo(const char *obj_key, int n) { + try { + fa_ptr obj = get_fa_object(obj_key); + obj->set_wo(n); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_wo : ", e.what()); + } } /**************************************************************************/ /* Fourier Analysis Results */ /**************************************************************************/ -int gn_fa_result(double* result, const char** rkeys, size_t rkeys_size, - const double* rvalues, size_t rvalues_size, const char* rkey) -{ - try { - util::check_pointer(result); - if (rkeys_size != rvalues_size) { - throw std::runtime_error("Size of result keys does not match size of result values"); - } - size_t key_index = get_fa_result_key_index(rkeys, rkeys_size, rkey); - *result = rvalues[key_index]; - return gn_success; - } catch (const std::exception& e) { - *result = 0.0; - return util::return_on_exception("gn_fa_result : ", e.what()); - } -} - -int gn_fa_result_string(char* result, size_t result_size, const char** rkeys, size_t rkeys_size, - const double* rvalues, size_t rvalues_size, const char* rkey) -{ - try { - util::check_pointer(result); - std::string rstr = get_fa_result_string(rkeys, rkeys_size, rvalues, rvalues_size, rkey); - util::fill_string_buffer(rstr.data(), rstr.size(), result, result_size); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fa_result_string : ", e.what()); - } +int gn_fa_result(double *result, const char **rkeys, size_t rkeys_size, + const double *rvalues, size_t rvalues_size, const char *rkey) { + try { + util::check_pointer(result); + if (rkeys_size != rvalues_size) { + throw std::runtime_error( + "Size of result keys does not match size of result values"); + } + size_t key_index = + get_fa_result_key_index(rkeys, rkeys_size, rkey); + *result = rvalues[key_index]; + return gn_success; + } catch (const std::exception &e) { + *result = 0.0; + return util::return_on_exception("gn_fa_result : ", e.what()); + } +} + +int gn_fa_result_string(char *result, size_t result_size, const char **rkeys, + size_t rkeys_size, const double *rvalues, + size_t rvalues_size, const char *rkey) { + try { + util::check_pointer(result); + std::string rstr = get_fa_result_string( + rkeys, rkeys_size, rvalues, rvalues_size, rkey); + util::fill_string_buffer(rstr.data(), rstr.size(), result, + result_size); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fa_result_string : ", + e.what()); + } } /**************************************************************************/ /* Fourier Analysis Helpers */ /**************************************************************************/ -int gn_fa_load_key_size(size_t* size, const char* filename, const char* obj_key) -{ - try { - util::check_pointer(size); - std::string key (obj_key); - if (key.empty()) { - key = util::get_object_key_from_filename(filename); - } - *size = util::terminated_size(key.size()); - return gn_success; - } catch (const std::exception& e) { - *size = 0; - return util::return_on_exception("gn_fa_load_key_size : ", e.what()); - } -} - -int gn_fa_preview_size(size_t* size, const char* cfg_id, bool cplx) -{ - try { - util::check_pointer(size); - fa_ptr obj = get_fa_object_or_load_from_file(cfg_id); - std::string s = obj->preview(cplx); - *size = util::terminated_size(s.size()); - return gn_success; - } catch (const std::exception& e) { - *size = 0; - return util::return_on_exception("gn_fa_preview_size : ", e.what()); - } -} - -int gn_fa_result_string_size(size_t* size, const char** rkeys, size_t rkeys_size, - const double* rvalues, size_t rvalues_size, const char* rkey) -{ - try { - util::check_pointer(size); - std::string rstr = get_fa_result_string(rkeys, rkeys_size, rvalues, rvalues_size, rkey); - *size = util::terminated_size(rstr.size()); - return gn_success; - } catch (const std::exception& e) { - *size = 0; - return util::return_on_exception("gn_fa_result_string_size : ", e.what()); - } -} - -int gn_fft_analysis_results_key_sizes(size_t* key_sizes, size_t key_sizes_size, - const char* cfg_id, size_t in_size, size_t nfft) -{ - try { - fa_ptr obj = get_fa_object_or_load_from_file(cfg_id); - std::vector key_sizes_src = obj->result_key_lengths(in_size, nfft); - if (key_sizes_src.size() != key_sizes_size) { - throw std::runtime_error("Number of keys does not match output array size"); - } - for (size_t i = 0; i < key_sizes_size; ++i) { - key_sizes[i] = util::terminated_size(key_sizes_src[i]); - } - return gn_success; - } catch (const std::exception& e) { - std::fill(key_sizes, key_sizes + key_sizes_size, 0); - return util::return_on_exception("gn_fa_results_key_sizes : ", e.what()); - } -} - -int gn_fft_analysis_results_size(size_t* size, const char* cfg_id, size_t in_size, size_t nfft) -{ - try { - util::check_pointer(size); - fa_ptr obj = get_fa_object_or_load_from_file(cfg_id); - *size = obj->results_size(in_size, nfft); - return gn_success; - } catch (const std::exception& e) { - *size = 0; - return util::return_on_exception("gn_fa_results_size : ", e.what()); - } +int gn_fa_load_key_size(size_t *size, const char *filename, const char *obj_key) { + try { + util::check_pointer(size); + std::string key(obj_key); + if (key.empty()) { + key = util::get_object_key_from_filename(filename); + } + *size = util::terminated_size(key.size()); + return gn_success; + } catch (const std::exception &e) { + *size = 0; + return util::return_on_exception("gn_fa_load_key_size : ", + e.what()); + } +} + +int gn_fa_preview_size(size_t *size, const char *cfg_id, bool cplx) { + try { + util::check_pointer(size); + fa_ptr obj = get_fa_object_or_load_from_file(cfg_id); + std::string s = obj->preview(cplx); + *size = util::terminated_size(s.size()); + return gn_success; + } catch (const std::exception &e) { + *size = 0; + return util::return_on_exception("gn_fa_preview_size : ", + e.what()); + } +} + +int gn_fa_result_string_size(size_t *size, const char **rkeys, + size_t rkeys_size, const double *rvalues, + size_t rvalues_size, const char *rkey) { + try { + util::check_pointer(size); + std::string rstr = get_fa_result_string( + rkeys, rkeys_size, rvalues, rvalues_size, rkey); + *size = util::terminated_size(rstr.size()); + return gn_success; + } catch (const std::exception &e) { + *size = 0; + return util::return_on_exception("gn_fa_result_string_size : ", + e.what()); + } +} + +int gn_fft_analysis_results_key_sizes(size_t *key_sizes, size_t key_sizes_size, + const char *cfg_id, size_t in_size, + size_t nfft) { + try { + fa_ptr obj = get_fa_object_or_load_from_file(cfg_id); + std::vector key_sizes_src = + obj->result_key_lengths(in_size, nfft); + if (key_sizes_src.size() != key_sizes_size) { + throw std::runtime_error( + "Number of keys does not match output array size"); + } + for (size_t i = 0; i < key_sizes_size; ++i) { + key_sizes[i] = util::terminated_size(key_sizes_src[i]); + } + return gn_success; + } catch (const std::exception &e) { + std::fill(key_sizes, key_sizes + key_sizes_size, 0); + return util::return_on_exception("gn_fa_results_key_sizes : ", + e.what()); + } +} + +int gn_fft_analysis_results_size(size_t *size, const char *cfg_id, + size_t in_size, size_t nfft) { + try { + util::check_pointer(size); + fa_ptr obj = get_fa_object_or_load_from_file(cfg_id); + *size = obj->results_size(in_size, nfft); + return gn_success; + } catch (const std::exception &e) { + *size = 0; + return util::return_on_exception("gn_fa_results_size : ", + e.what()); + } } /**************************************************************************/ @@ -1125,320 +1158,317 @@ int gn_fft_analysis_results_size(size_t* size, const char* cfg_id, size_t in_siz namespace { - template - int gn_fftxx(const char* suffix, double* out, size_t out_size, - const T* i, size_t i_size, const T* q, size_t q_size, - int n, size_t navg, size_t nfft, GnWindow window, GnCodeFormat format) - { - try { - gn::Window w = gn::get_enum(window); - gn::CodeFormat f = gn::get_enum(format); - gn::fft(i, i_size, q, q_size, out, out_size, n, navg, nfft, w, f); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fft", suffix, " : ", e.what()); - } - } - - template - int gn_rfftxx(const char* suffix, double* out, size_t out_size, - const T* in, size_t in_size, - int n, size_t navg, size_t nfft, GnWindow window, GnCodeFormat format, GnRfftScale scale) - { - try { - gn::Window w = gn::get_enum(window); - gn::CodeFormat f = gn::get_enum(format); - gn::RfftScale s = gn::get_enum(scale); - gn::rfft(in, in_size, out, out_size, n, navg, nfft, w, f, s); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_rfft", suffix, " : ", e.what()); - } - } - -} // namespace anonymous - -int gn_fft(double* out, size_t out_size, - const double* i, size_t i_size, const double* q, size_t q_size, - size_t navg, size_t nfft, GnWindow window) -{ - try { - gn::Window w = gn::get_enum(window); - gn::fft(i, i_size, q, q_size, out, out_size, navg, nfft, w); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fft : ", e.what()); - } -} - -int gn_fft16(double* out, size_t out_size, - const int16_t* i, size_t i_size, const int16_t* q, size_t q_size, - int n, size_t navg, size_t nfft, GnWindow window, GnCodeFormat format) -{ - return gn_fftxx("16", out, out_size, i, i_size, q, q_size, n, navg, nfft, window, format); -} - -int gn_fft32(double* out, size_t out_size, - const int32_t* i, size_t i_size, const int32_t* q, size_t q_size, - int n, size_t navg, size_t nfft, GnWindow window, GnCodeFormat format) -{ - return gn_fftxx("32", out, out_size, i, i_size, q, q_size, n, navg, nfft, window, format); -} - -int gn_fft64(double* out, size_t out_size, - const int64_t* i, size_t i_size, const int64_t* q, size_t q_size, - int n, size_t navg, size_t nfft, GnWindow window, GnCodeFormat format) -{ - return gn_fftxx("64", out, out_size, i, i_size, q, q_size, n, navg, nfft, window, format); -} - -int gn_rfft(double* out, size_t out_size, const double* in, size_t in_size, - size_t navg, size_t nfft, GnWindow window, GnRfftScale scale) -{ - try { - gn::Window w = gn::get_enum(window); - gn::RfftScale s = gn::get_enum(scale); - gn::rfft(in, in_size, out, out_size, navg, nfft, w, s); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_rfft : ", e.what()); - } -} - -int gn_rfft16(double* out, size_t out_size, const int16_t* in, size_t in_size, - int n, size_t navg, size_t nfft, GnWindow window, GnCodeFormat format, GnRfftScale scale) -{ - return gn_rfftxx("16", out, out_size, in, in_size, n, navg, nfft, window, format, scale); -} - -int gn_rfft32(double* out, size_t out_size, const int32_t* in, size_t in_size, - int n, size_t navg, size_t nfft, GnWindow window, GnCodeFormat format, GnRfftScale scale) -{ - return gn_rfftxx("32", out, out_size, in, in_size, n, navg, nfft, window, format, scale); -} - -int gn_rfft64(double* out, size_t out_size, const int64_t* in, size_t in_size, - int n, size_t navg, size_t nfft, GnWindow window, GnCodeFormat format, GnRfftScale scale) -{ - return gn_rfftxx("64", out, out_size, in, in_size, n, navg, nfft, window, format, scale); +template +int gn_fftxx(const char *suffix, double *out, size_t out_size, const T *i, + size_t i_size, const T *q, size_t q_size, int n, size_t navg, + size_t nfft, GnWindow window, GnCodeFormat format) { + try { + gn::Window w = gn::get_enum(window); + gn::CodeFormat f = gn::get_enum(format); + gn::fft(i, i_size, q, q_size, out, out_size, n, navg, nfft, w, + f); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fft", suffix, " : ", + e.what()); + } +} + +template +int gn_rfftxx(const char *suffix, double *out, size_t out_size, const T *in, + size_t in_size, int n, size_t navg, size_t nfft, GnWindow window, + GnCodeFormat format, GnRfftScale scale) { + try { + gn::Window w = gn::get_enum(window); + gn::CodeFormat f = gn::get_enum(format); + gn::RfftScale s = gn::get_enum(scale); + gn::rfft(in, in_size, out, out_size, n, navg, nfft, w, f, s); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_rfft", suffix, " : ", + e.what()); + } +} + +} // namespace + +int gn_fft(double *out, size_t out_size, const double *i, size_t i_size, + const double *q, size_t q_size, size_t navg, size_t nfft, + GnWindow window) { + try { + gn::Window w = gn::get_enum(window); + gn::fft(i, i_size, q, q_size, out, out_size, navg, nfft, w); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fft : ", e.what()); + } +} + +int gn_fft16(double *out, size_t out_size, const int16_t *i, size_t i_size, + const int16_t *q, size_t q_size, int n, size_t navg, size_t nfft, + GnWindow window, GnCodeFormat format) { + return gn_fftxx("16", out, out_size, i, i_size, q, q_size, n, navg, + nfft, window, format); +} + +int gn_fft32(double *out, size_t out_size, const int32_t *i, size_t i_size, + const int32_t *q, size_t q_size, int n, size_t navg, size_t nfft, + GnWindow window, GnCodeFormat format) { + return gn_fftxx("32", out, out_size, i, i_size, q, q_size, n, navg, + nfft, window, format); +} + +int gn_fft64(double *out, size_t out_size, const int64_t *i, size_t i_size, + const int64_t *q, size_t q_size, int n, size_t navg, size_t nfft, + GnWindow window, GnCodeFormat format) { + return gn_fftxx("64", out, out_size, i, i_size, q, q_size, n, navg, + nfft, window, format); +} + +int gn_rfft(double *out, size_t out_size, const double *in, size_t in_size, + size_t navg, size_t nfft, GnWindow window, GnRfftScale scale) { + try { + gn::Window w = gn::get_enum(window); + gn::RfftScale s = gn::get_enum(scale); + gn::rfft(in, in_size, out, out_size, navg, nfft, w, s); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_rfft : ", e.what()); + } +} + +int gn_rfft16(double *out, size_t out_size, const int16_t *in, size_t in_size, + int n, size_t navg, size_t nfft, GnWindow window, + GnCodeFormat format, GnRfftScale scale) { + return gn_rfftxx("16", out, out_size, in, in_size, n, navg, nfft, + window, format, scale); +} + +int gn_rfft32(double *out, size_t out_size, const int32_t *in, size_t in_size, + int n, size_t navg, size_t nfft, GnWindow window, + GnCodeFormat format, GnRfftScale scale) { + return gn_rfftxx("32", out, out_size, in, in_size, n, navg, nfft, + window, format, scale); +} + +int gn_rfft64(double *out, size_t out_size, const int64_t *in, size_t in_size, + int n, size_t navg, size_t nfft, GnWindow window, + GnCodeFormat format, GnRfftScale scale) { + return gn_rfftxx("64", out, out_size, in, in_size, n, navg, nfft, + window, format, scale); } /**************************************************************************/ /* Fourier Transform Helpers */ /**************************************************************************/ -int gn_fft_size(size_t* out_size, size_t i_size, size_t q_size, size_t navg, size_t nfft) -{ - try { - util::check_pointer(out_size); - *out_size = gn::fft_size(i_size, q_size, navg, nfft); - return gn_success; - } catch (const std::exception& e) { - *out_size = 0; - return util::return_on_exception("gn_fft_size : ", e.what()); - } -} - -int gn_rfft_size(size_t* out_size, size_t in_size, size_t navg, size_t nfft) -{ - try { - util::check_pointer(out_size); - *out_size = gn::rfft_size(in_size, navg, nfft); - return gn_success; - } catch (const std::exception& e) { - *out_size = 0; - return util::return_on_exception("gn_rfft_size : ", e.what()); - } +int gn_fft_size(size_t *out_size, size_t i_size, size_t q_size, size_t navg, + size_t nfft) { + try { + util::check_pointer(out_size); + *out_size = gn::fft_size(i_size, q_size, navg, nfft); + return gn_success; + } catch (const std::exception &e) { + *out_size = 0; + return util::return_on_exception("gn_fft_size : ", e.what()); + } +} + +int gn_rfft_size(size_t *out_size, size_t in_size, size_t navg, size_t nfft) { + try { + util::check_pointer(out_size); + *out_size = gn::rfft_size(in_size, navg, nfft); + return gn_success; + } catch (const std::exception &e) { + *out_size = 0; + return util::return_on_exception("gn_rfft_size : ", e.what()); + } } /**************************************************************************/ /* Fourier Utilities */ /**************************************************************************/ -int gn_alias(double* out, double fs, double freq, GnFreqAxisType axis_type) -{ - try { - util::check_pointer(out); - gn::FreqAxisType at = gn::get_enum(axis_type); - *out = gn::alias(fs, freq, at); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_alias : ", e.what()); - } -} - -int gn_coherent(double* out, size_t nfft, double fs, double freq) -{ - try { - util::check_pointer(out); - *out = gn::coherent(nfft, fs, freq); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_coherent : ", e.what()); - } -} - -int gn_fftshift(double* out, size_t out_size, const double* in, size_t in_size) -{ - try { - gn::fftshift(in, in_size, out, out_size); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fftshift : ", e.what()); - } -} - -int gn_freq_axis(double* out, size_t size, - size_t nfft, GnFreqAxisType axis_type, double fs, GnFreqAxisFormat axis_format) -{ - try { - gn::FreqAxisType at = gn::get_enum(axis_type); - gn::FreqAxisFormat af = gn::get_enum(axis_format); - gn::freq_axis(out, size, nfft, at, fs, af); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fftshift : ", e.what()); - } -} - -int gn_ifftshift(double* out, size_t out_size, const double* in, size_t in_size) -{ - try { - gn::ifftshift(in, in_size, out, out_size); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_ifftshift : ", e.what()); - } +int gn_alias(double *out, double fs, double freq, GnFreqAxisType axis_type) { + try { + util::check_pointer(out); + gn::FreqAxisType at = gn::get_enum(axis_type); + *out = gn::alias(fs, freq, at); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_alias : ", e.what()); + } +} + +int gn_coherent(double *out, size_t nfft, double fs, double freq) { + try { + util::check_pointer(out); + *out = gn::coherent(nfft, fs, freq); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_coherent : ", e.what()); + } +} + +int gn_fftshift(double *out, size_t out_size, const double *in, size_t in_size) { + try { + gn::fftshift(in, in_size, out, out_size); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fftshift : ", e.what()); + } +} + +int gn_freq_axis(double *out, size_t size, size_t nfft, + GnFreqAxisType axis_type, double fs, + GnFreqAxisFormat axis_format) { + try { + gn::FreqAxisType at = gn::get_enum(axis_type); + gn::FreqAxisFormat af = + gn::get_enum(axis_format); + gn::freq_axis(out, size, nfft, at, fs, af); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fftshift : ", e.what()); + } +} + +int gn_ifftshift(double *out, size_t out_size, const double *in, size_t in_size) { + try { + gn::ifftshift(in, in_size, out, out_size); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_ifftshift : ", e.what()); + } } /**************************************************************************/ /* Fourier Utility Helpers */ /**************************************************************************/ -int gn_freq_axis_size(size_t* size, size_t nfft, GnFreqAxisType axis_type) -{ - try { - util::check_pointer(size); - gn::FreqAxisType at = gn::get_enum(axis_type); - *size = gn::freq_axis_size(nfft, at); - return gn_success; - } catch (const std::exception& e) { - *size = 0; - return util::return_on_exception("gn_freq_axis_size : ", e.what()); - } +int gn_freq_axis_size(size_t *size, size_t nfft, GnFreqAxisType axis_type) { + try { + util::check_pointer(size); + gn::FreqAxisType at = gn::get_enum(axis_type); + *size = gn::freq_axis_size(nfft, at); + return gn_success; + } catch (const std::exception &e) { + *size = 0; + return util::return_on_exception("gn_freq_axis_size : ", + e.what()); + } } /**************************************************************************/ /* Manager */ /**************************************************************************/ -int gn_mgr_clear() -{ - gn::manager::clear(); - return gn_success; +int gn_mgr_clear() { + gn::manager::clear(); + return gn_success; } -int gn_mgr_compare(bool* result, const char* obj_key1, const char* obj_key2) -{ - try { - *result = gn::manager::equal(obj_key1, obj_key2); - return gn_success; - } catch (const std::exception& e) { - *result = false; - return util::return_on_exception("gn_mgr_equal : ", e.what()); - } +int gn_mgr_compare(bool *result, const char *obj_key1, const char *obj_key2) { + try { + *result = gn::manager::equal(obj_key1, obj_key2); + return gn_success; + } catch (const std::exception &e) { + *result = false; + return util::return_on_exception("gn_mgr_equal : ", e.what()); + } } -int gn_mgr_contains(bool* result, const char* obj_key) -{ - *result = gn::manager::contains(obj_key); - return gn_success; +int gn_mgr_contains(bool *result, const char *obj_key) { + *result = gn::manager::contains(obj_key); + return gn_success; } -int gn_mgr_remove(const char* obj_key) -{ - gn::manager::remove(obj_key); - return gn_success; +int gn_mgr_remove(const char *obj_key) { + gn::manager::remove(obj_key); + return gn_success; } -int gn_mgr_save(char* buf, size_t size, const char* obj_key, const char* filename) -{ - try { - std::string fn = gn::manager::save(obj_key, filename); - util::fill_string_buffer(fn.data(), fn.size(), buf, size); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_mgr_save : ", e.what()); - } +int gn_mgr_save(char *buf, size_t size, const char *obj_key, + const char *filename) { + try { + std::string fn = gn::manager::save(obj_key, filename); + util::fill_string_buffer(fn.data(), fn.size(), buf, size); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_mgr_save : ", e.what()); + } } -int gn_mgr_size(size_t* size) -{ - *size = gn::manager::size(); - return gn_success; +int gn_mgr_size(size_t *size) { + *size = gn::manager::size(); + return gn_success; } -int gn_mgr_to_string(char* buf, size_t size, const char* obj_key) -{ - try { - std::string s = gn::manager::to_string(obj_key); - util::fill_string_buffer(s.data(), s.size(), buf, size); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_mgr_to_string : ", e.what()); - } +int gn_mgr_to_string(char *buf, size_t size, const char *obj_key) { + try { + std::string s = gn::manager::to_string(obj_key); + util::fill_string_buffer(s.data(), s.size(), buf, size); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_mgr_to_string : ", + e.what()); + } } -int gn_mgr_type(char* buf, size_t size, const char* obj_key) -{ - try { - std::string s = gn::manager::type_str(obj_key); - util::fill_string_buffer(s.data(), s.size(), buf, size); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_mgr_type : ", e.what()); - } +int gn_mgr_type(char *buf, size_t size, const char *obj_key) { + try { + std::string s = gn::manager::type_str(obj_key); + util::fill_string_buffer(s.data(), s.size(), buf, size); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_mgr_type : ", e.what()); + } } /**************************************************************************/ /* Manager Helpers */ /**************************************************************************/ -int gn_mgr_save_filename_size(size_t* size, const char* obj_key, const char* filename) -{ - try { - util::check_pointer(size); - size_t fn_size = gn::manager::get_filename_from_object_key(obj_key, filename).size(); - *size = util::terminated_size(fn_size); - return gn_success; - } catch (const std::exception& e) { - *size = 0; - return util::return_on_exception("gn_mgr_save_filename_size : ", e.what()); - } -} - -int gn_mgr_to_string_size(size_t* size, const char* obj_key) -{ - try { - util::check_pointer(size); - *size = util::terminated_size(gn::manager::to_string(obj_key).size()); - return gn_success; - } catch (const std::exception& e) { - *size = 0; - return util::return_on_exception("gn_mgr_to_string_size : ", e.what()); - } -} - -int gn_mgr_type_size(size_t* size, const char* obj_key) -{ - try { - util::check_pointer(size); - *size = util::terminated_size(gn::manager::type_str(obj_key).size()); - return gn_success; - } catch (const std::exception& e) { - *size = 0; - return util::return_on_exception("gn_mgr_type_size : ", e.what()); - } +int gn_mgr_save_filename_size(size_t *size, const char *obj_key, + const char *filename) { + try { + util::check_pointer(size); + size_t fn_size = gn::manager::get_filename_from_object_key( + obj_key, filename) + .size(); + *size = util::terminated_size(fn_size); + return gn_success; + } catch (const std::exception &e) { + *size = 0; + return util::return_on_exception("gn_mgr_save_filename_size : ", + e.what()); + } +} + +int gn_mgr_to_string_size(size_t *size, const char *obj_key) { + try { + util::check_pointer(size); + *size = util::terminated_size( + gn::manager::to_string(obj_key).size()); + return gn_success; + } catch (const std::exception &e) { + *size = 0; + return util::return_on_exception("gn_mgr_to_string_size : ", + e.what()); + } +} + +int gn_mgr_type_size(size_t *size, const char *obj_key) { + try { + util::check_pointer(size); + *size = util::terminated_size( + gn::manager::type_str(obj_key).size()); + return gn_success; + } catch (const std::exception &e) { + *size = 0; + return util::return_on_exception("gn_mgr_type_size : ", + e.what()); + } } /**************************************************************************/ @@ -1447,189 +1477,189 @@ int gn_mgr_type_size(size_t* size, const char* obj_key) namespace { - template - int gn_downsamplex(const char* suffix, T* out, size_t out_size, - const T* in, size_t in_size, int ratio, bool interleaved) - { - try { - gn::downsample(in, in_size, out, out_size, ratio, interleaved); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_downsample", suffix, " : ", e.what()); - } - } - - template - int gn_fshiftx(const char* suffix, T* out, size_t out_size, - const T* i, size_t i_size, const T* q, size_t q_size, - int n, double fs, double fshift, GnCodeFormat format) - { - try { - gn::CodeFormat f = gn::get_enum(format); - gn::fshift(i, i_size, q, q_size, out, out_size, n, fs, fshift, f); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fshift", suffix, " : ", e.what()); - } - } - - template - int gn_normalize(const char* suffix, double* out, size_t out_size, - const T* in, size_t in_size, int n, GnCodeFormat format) - { - try { - gn::CodeFormat f = gn::get_enum(format); - gn::normalize(in, in_size, out, out_size, n, f); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_normalize", suffix, " : ", e.what()); - } - } - - template - int gn_quantize(const char* suffix, T* out, size_t out_size, - const double* in, size_t in_size, double fsr, int n, double noise, GnCodeFormat format) - { - try { - gn::CodeFormat f = gn::get_enum(format); - gn::quantize(in, in_size, out, out_size, fsr, n, noise, f); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_quantize", suffix, " : ", e.what()); - } - } - -} // namespace anonymous - -int gn_downsample(double* out, size_t out_size, - const double* in, size_t in_size, int ratio, bool interleaved) -{ - return gn_downsamplex("", out, out_size, in, in_size, ratio, interleaved); -} - -int gn_downsample16(int16_t* out, size_t out_size, - const int16_t* in, size_t in_size, int ratio, bool interleaved) -{ - return gn_downsamplex("16", out, out_size, in, in_size, ratio, interleaved); -} - -int gn_downsample32(int32_t* out, size_t out_size, - const int32_t* in, size_t in_size, int ratio, bool interleaved) -{ - return gn_downsamplex("32", out, out_size, in, in_size, ratio, interleaved); -} - -int gn_downsample64(int64_t* out, size_t out_size, - const int64_t* in, size_t in_size, int ratio, bool interleaved) -{ - return gn_downsamplex("64", out, out_size, in, in_size, ratio, interleaved); -} - -int gn_fshift(double* out, size_t out_size, - const double* i, size_t i_size, const double* q, size_t q_size, double fs, double fshift) -{ - try { - gn::fshift(i, i_size, q, q_size, out, out_size, fs, fshift); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_fshift : ", e.what()); - } -} - -int gn_fshift16(int16_t* out, size_t out_size, - const int16_t* i, size_t i_size, const int16_t* q, size_t q_size, - int n, double fs, double fshift, GnCodeFormat format) -{ - return gn_fshiftx("16", out, out_size, i, i_size, q, q_size, n, fs, fshift, format); -} - -int gn_fshift32(int32_t* out, size_t out_size, - const int32_t* i, size_t i_size, const int32_t* q, size_t q_size, - int n, double fs, double fshift, GnCodeFormat format) -{ - return gn_fshiftx("32", out, out_size, i, i_size, q, q_size, n, fs, fshift, format); -} - -int gn_fshift64(int64_t* out, size_t out_size, - const int64_t* i, size_t i_size, const int64_t* q, size_t q_size, - int n, double fs, double fshift, GnCodeFormat format) -{ - return gn_fshiftx("64", out, out_size, i, i_size, q, q_size, n, fs, fshift, format); -} - -int gn_normalize16(double* out, size_t out_size, - const int16_t* in, size_t in_size, int n, GnCodeFormat format) -{ - return gn_normalize("16", out, out_size, in, in_size, n, format); -} - -int gn_normalize32(double* out, size_t out_size, - const int32_t* in, size_t in_size, int n, GnCodeFormat format) -{ - return gn_normalize("32", out, out_size, in, in_size, n, format); +template +int gn_downsamplex(const char *suffix, T *out, size_t out_size, const T *in, + size_t in_size, int ratio, bool interleaved) { + try { + gn::downsample(in, in_size, out, out_size, ratio, interleaved); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_downsample", suffix, " : ", + e.what()); + } +} + +template +int gn_fshiftx(const char *suffix, T *out, size_t out_size, const T *i, + size_t i_size, const T *q, size_t q_size, int n, double fs, + double fshift, GnCodeFormat format) { + try { + gn::CodeFormat f = gn::get_enum(format); + gn::fshift(i, i_size, q, q_size, out, out_size, n, fs, fshift, + f); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fshift", suffix, " : ", + e.what()); + } +} + +template +int gn_normalize(const char *suffix, double *out, size_t out_size, const T *in, + size_t in_size, int n, GnCodeFormat format) { + try { + gn::CodeFormat f = gn::get_enum(format); + gn::normalize(in, in_size, out, out_size, n, f); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_normalize", suffix, " : ", + e.what()); + } +} + +template +int gn_quantize(const char *suffix, T *out, size_t out_size, const double *in, + size_t in_size, double fsr, int n, double noise, + GnCodeFormat format) { + try { + gn::CodeFormat f = gn::get_enum(format); + gn::quantize(in, in_size, out, out_size, fsr, n, noise, f); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_quantize", suffix, " : ", + e.what()); + } +} + +} // namespace + +int gn_downsample(double *out, size_t out_size, const double *in, + size_t in_size, int ratio, bool interleaved) { + return gn_downsamplex("", out, out_size, in, in_size, ratio, + interleaved); +} + +int gn_downsample16(int16_t *out, size_t out_size, const int16_t *in, + size_t in_size, int ratio, bool interleaved) { + return gn_downsamplex("16", out, out_size, in, in_size, ratio, + interleaved); +} + +int gn_downsample32(int32_t *out, size_t out_size, const int32_t *in, + size_t in_size, int ratio, bool interleaved) { + return gn_downsamplex("32", out, out_size, in, in_size, ratio, + interleaved); +} + +int gn_downsample64(int64_t *out, size_t out_size, const int64_t *in, + size_t in_size, int ratio, bool interleaved) { + return gn_downsamplex("64", out, out_size, in, in_size, ratio, + interleaved); +} + +int gn_fshift(double *out, size_t out_size, const double *i, size_t i_size, + const double *q, size_t q_size, double fs, double fshift) { + try { + gn::fshift(i, i_size, q, q_size, out, out_size, fs, fshift); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_fshift : ", e.what()); + } +} + +int gn_fshift16(int16_t *out, size_t out_size, const int16_t *i, size_t i_size, + const int16_t *q, size_t q_size, int n, double fs, + double fshift, GnCodeFormat format) { + return gn_fshiftx("16", out, out_size, i, i_size, q, q_size, n, fs, + fshift, format); +} + +int gn_fshift32(int32_t *out, size_t out_size, const int32_t *i, size_t i_size, + const int32_t *q, size_t q_size, int n, double fs, + double fshift, GnCodeFormat format) { + return gn_fshiftx("32", out, out_size, i, i_size, q, q_size, n, fs, + fshift, format); +} + +int gn_fshift64(int64_t *out, size_t out_size, const int64_t *i, size_t i_size, + const int64_t *q, size_t q_size, int n, double fs, + double fshift, GnCodeFormat format) { + return gn_fshiftx("64", out, out_size, i, i_size, q, q_size, n, fs, + fshift, format); +} + +int gn_normalize16(double *out, size_t out_size, const int16_t *in, + size_t in_size, int n, GnCodeFormat format) { + return gn_normalize("16", out, out_size, in, in_size, n, format); +} + +int gn_normalize32(double *out, size_t out_size, const int32_t *in, + size_t in_size, int n, GnCodeFormat format) { + return gn_normalize("32", out, out_size, in, in_size, n, format); } -int gn_normalize64(double* out, size_t out_size, - const int64_t* in, size_t in_size, int n, GnCodeFormat format) -{ - return gn_normalize("64", out, out_size, in, in_size, n, format); +int gn_normalize64(double *out, size_t out_size, const int64_t *in, + size_t in_size, int n, GnCodeFormat format) { + return gn_normalize("64", out, out_size, in, in_size, n, format); } -int gn_polyval(double* out, size_t out_size, - const double* in, size_t in_size, const double* c, size_t c_size) -{ - try { - gn::polyval(in, in_size, out, out_size, c, c_size); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_polyval : ", e.what()); - } +int gn_polyval(double *out, size_t out_size, const double *in, size_t in_size, + const double *c, size_t c_size) { + try { + gn::polyval(in, in_size, out, out_size, c, c_size); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_polyval : ", e.what()); + } } -int gn_quantize16(int16_t* out, size_t out_size, - const double* in, size_t in_size, double fsr, int n, double noise, GnCodeFormat format) -{ - return gn_quantize("16", out, out_size, in, in_size, fsr, n, noise, format); +int gn_quantize16(int16_t *out, size_t out_size, const double *in, + size_t in_size, double fsr, int n, double noise, + GnCodeFormat format) { + return gn_quantize("16", out, out_size, in, in_size, fsr, n, noise, + format); } -int gn_quantize32(int32_t* out, size_t out_size, - const double* in, size_t in_size, double fsr, int n, double noise, GnCodeFormat format) -{ - return gn_quantize("32", out, out_size, in, in_size, fsr, n, noise, format); +int gn_quantize32(int32_t *out, size_t out_size, const double *in, + size_t in_size, double fsr, int n, double noise, + GnCodeFormat format) { + return gn_quantize("32", out, out_size, in, in_size, fsr, n, noise, + format); } -int gn_quantize64(int64_t* out, size_t out_size, - const double* in, size_t in_size, double fsr, int n, double noise, GnCodeFormat format) -{ - return gn_quantize("64", out, out_size, in, in_size, fsr, n, noise, format); +int gn_quantize64(int64_t *out, size_t out_size, const double *in, + size_t in_size, double fsr, int n, double noise, + GnCodeFormat format) { + return gn_quantize("64", out, out_size, in, in_size, fsr, n, noise, + format); } /**************************************************************************/ /* Signal Processing Helpers */ /**************************************************************************/ -int gn_downsample_size(size_t* out_size, size_t in_size, int ratio, bool interleaved) -{ - try { - util::check_pointer(out_size); - *out_size = gn::downsample_size(in_size, ratio, interleaved); - return gn_success; - } catch (const std::exception& e) { - *out_size = 0; - return util::return_on_exception("gn_downsample_size : ", e.what()); - } -} - -int gn_fshift_size(size_t* out_size, size_t i_size, size_t q_size) -{ - try { - util::check_pointer(out_size); - *out_size = gn::fshift_size(i_size, q_size); - return gn_success; - } catch (const std::exception& e) { - *out_size = 0; - return util::return_on_exception("gn_fshift_size : ", e.what()); - } +int gn_downsample_size(size_t *out_size, size_t in_size, int ratio, + bool interleaved) { + try { + util::check_pointer(out_size); + *out_size = gn::downsample_size(in_size, ratio, interleaved); + return gn_success; + } catch (const std::exception &e) { + *out_size = 0; + return util::return_on_exception("gn_downsample_size : ", + e.what()); + } +} + +int gn_fshift_size(size_t *out_size, size_t i_size, size_t q_size) { + try { + util::check_pointer(out_size); + *out_size = gn::fshift_size(i_size, q_size); + return gn_success; + } catch (const std::exception &e) { + *out_size = 0; + return util::return_on_exception("gn_fshift_size : ", e.what()); + } } /**************************************************************************/ @@ -1638,99 +1668,100 @@ int gn_fshift_size(size_t* out_size, size_t i_size, size_t q_size) namespace { - template - int gn_wf_analysisx(const char* suffix, - char** rkeys, size_t rkeys_size, double* rvalues, size_t rvalues_size, - const T* in, size_t in_size) - { - try { - util::check_pointer(rkeys); - util::check_pointer(rvalues); - const std::vector& keys = gn::wf_analysis_ordered_keys(); - if (keys.size() != rkeys_size) { - throw std::runtime_error("Size of result key array is wrong"); - } - if (rvalues_size != rkeys_size) { - throw std::runtime_error("Size of result keys does not match size of result values"); - } - std::map results = gn::wf_analysis(in, in_size); - for (size_t i = 0; i < keys.size(); ++i) { - const std::string& src = keys[i]; - char* dst = rkeys[i]; - size_t dst_size = util::terminated_size(src.size()); - util::fill_string_buffer(src.data(), src.size(), dst, dst_size); - rvalues[i] = results.at(src); - } - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_wf_analysis", suffix, " : ", e.what()); - } - } - -} // namespace anonymous - -int gn_cos(double* out, size_t size, - double fs, double ampl, double freq, double phase, double td, double tj) -{ - try { - gn::cos(out, size, fs, ampl, freq, phase, td, tj); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_cos : ", e.what()); - } -} - -int gn_gaussian(double* out, size_t size, double mean, double sd) -{ - try { - gn::gaussian(out, size, mean, sd); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_gaussian : ", e.what()); - } -} - -int gn_ramp(double* out, size_t size, double start, double stop, double noise) -{ - try { - gn::ramp(out, size, start, stop, noise); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_ramp : ", e.what()); - } -} - -int gn_sin(double* out, size_t size, - double fs, double ampl, double freq, double phase, double td, double tj) -{ - try { - gn::sin(out, size, fs, ampl, freq, phase, td, tj); - return gn_success; - } catch (const std::exception& e) { - return util::return_on_exception("gn_sin : ", e.what()); - } -} - -int gn_wf_analysis(char** rkeys, size_t rkeys_size, double* rvalues, size_t rvalues_size, - const double* in, size_t in_size) -{ - return gn_wf_analysisx("", rkeys, rkeys_size, rvalues, rvalues_size, in, in_size); -} - -int gn_wf_analysis16(char** rkeys, size_t rkeys_size, double* rvalues, size_t rvalues_size, - const int16_t* in, size_t in_size) -{ - return gn_wf_analysisx("16", rkeys, rkeys_size, rvalues, rvalues_size, in, in_size); -} - -int gn_wf_analysis32(char** rkeys, size_t rkeys_size, double* rvalues, size_t rvalues_size, - const int32_t* in, size_t in_size) -{ - return gn_wf_analysisx("32", rkeys, rkeys_size, rvalues, rvalues_size, in, in_size); -} - -int gn_wf_analysis64(char** rkeys, size_t rkeys_size, double* rvalues, size_t rvalues_size, - const int64_t* in, size_t in_size) -{ - return gn_wf_analysisx("64", rkeys, rkeys_size, rvalues, rvalues_size, in, in_size); +template +int gn_wf_analysisx(const char *suffix, char **rkeys, size_t rkeys_size, + double *rvalues, size_t rvalues_size, const T *in, + size_t in_size) { + try { + util::check_pointer(rkeys); + util::check_pointer(rvalues); + const std::vector &keys = + gn::wf_analysis_ordered_keys(); + if (keys.size() != rkeys_size) { + throw std::runtime_error( + "Size of result key array is wrong"); + } + if (rvalues_size != rkeys_size) { + throw std::runtime_error( + "Size of result keys does not match size of result values"); + } + std::map results = + gn::wf_analysis(in, in_size); + for (size_t i = 0; i < keys.size(); ++i) { + const std::string &src = keys[i]; + char *dst = rkeys[i]; + size_t dst_size = util::terminated_size(src.size()); + util::fill_string_buffer(src.data(), src.size(), dst, + dst_size); + rvalues[i] = results.at(src); + } + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_wf_analysis", suffix, + " : ", e.what()); + } +} + +} // namespace + +int gn_cos(double *out, size_t size, double fs, double ampl, double freq, + double phase, double td, double tj) { + try { + gn::cos(out, size, fs, ampl, freq, phase, td, tj); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_cos : ", e.what()); + } +} + +int gn_gaussian(double *out, size_t size, double mean, double sd) { + try { + gn::gaussian(out, size, mean, sd); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_gaussian : ", e.what()); + } +} + +int gn_ramp(double *out, size_t size, double start, double stop, double noise) { + try { + gn::ramp(out, size, start, stop, noise); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_ramp : ", e.what()); + } +} + +int gn_sin(double *out, size_t size, double fs, double ampl, double freq, + double phase, double td, double tj) { + try { + gn::sin(out, size, fs, ampl, freq, phase, td, tj); + return gn_success; + } catch (const std::exception &e) { + return util::return_on_exception("gn_sin : ", e.what()); + } +} + +int gn_wf_analysis(char **rkeys, size_t rkeys_size, double *rvalues, + size_t rvalues_size, const double *in, size_t in_size) { + return gn_wf_analysisx("", rkeys, rkeys_size, rvalues, rvalues_size, in, + in_size); +} + +int gn_wf_analysis16(char **rkeys, size_t rkeys_size, double *rvalues, + size_t rvalues_size, const int16_t *in, size_t in_size) { + return gn_wf_analysisx("16", rkeys, rkeys_size, rvalues, rvalues_size, + in, in_size); +} + +int gn_wf_analysis32(char **rkeys, size_t rkeys_size, double *rvalues, + size_t rvalues_size, const int32_t *in, size_t in_size) { + return gn_wf_analysisx("32", rkeys, rkeys_size, rvalues, rvalues_size, + in, in_size); +} + +int gn_wf_analysis64(char **rkeys, size_t rkeys_size, double *rvalues, + size_t rvalues_size, const int64_t *in, size_t in_size) { + return gn_wf_analysisx("64", rkeys, rkeys_size, rvalues, rvalues_size, + in, in_size); } \ No newline at end of file diff --git a/bindings/c/src/cgenalyzer_simplified_beta.cpp b/bindings/c/src/cgenalyzer_simplified_beta.cpp index 264e8ae..b38e435 100644 --- a/bindings/c/src/cgenalyzer_simplified_beta.cpp +++ b/bindings/c/src/cgenalyzer_simplified_beta.cpp @@ -1,1169 +1,1108 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #include "cgenalyzer_simplified_beta.h" #include "cgenalyzer_private.h" extern "C" { - int gn_config_free(gn_config *c) - { - if ((*c)->obj_key){ - gn_mgr_remove((*c)->obj_key); - free((*c)->obj_key); - } - if ((*c)->comp_key){ - gn_fa_remove_comp((*c)->obj_key, (*c)->comp_key); - free((*c)->comp_key); - } - if (((*c)->_fa_results_size) > 0) - { - for (size_t i = 0; i < (*c)->_fa_results_size; i++) - free((*c)->_fa_result_keys[i]); - free((*c)->_fa_result_keys); - free((*c)->_fa_result_key_sizes); - free((*c)->_fa_result_values); - } - if (((*c)->_wfa_results_size) > 0) - { - for (size_t i = 0; i < (*c)->_wfa_results_size; i++) - free((*c)->_wfa_result_keys[i]); - free((*c)->_wfa_result_keys); - free((*c)->_wfa_result_key_sizes); - free((*c)->_wfa_result_values); - } - if (((*c)->_hist_results_size) > 0) - { - for (size_t i = 0; i < (*c)->_hist_results_size; i++) - free((*c)->_hist_result_keys[i]); - free((*c)->_hist_result_keys); - free((*c)->_hist_result_key_sizes); - free((*c)->_hist_result_values); - } - if (((*c)->_dnl_results_size) > 0) - { - for (size_t i = 0; i < (*c)->_dnl_results_size; i++) - free((*c)->_dnl_result_keys[i]); - free((*c)->_dnl_result_keys); - free((*c)->_dnl_result_key_sizes); - free((*c)->_dnl_result_values); - } - if (((*c)->_inl_results_size) > 0) - { - for (size_t i = 0; i < (*c)->_inl_results_size; i++) - free((*c)->_inl_result_keys[i]); - free((*c)->_inl_result_keys); - free((*c)->_inl_result_key_sizes); - free((*c)->_inl_result_values); - } - free(*c); - - return gn_success; - } - - int gn_config_set_ttype(tone_type ttype, gn_config *c) - { - if (!((ttype == REAL_COSINE) || (ttype == REAL_SINE) || (ttype == COMPLEX_EXP))) - { - printf("ERROR: Invalid selection of ttype for tone generation\n"); - return gn_failure; - } - - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->ttype = ttype; - - return gn_success; - } - - int gn_config_set_npts(size_t npts, gn_config *c) - { - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->npts = npts; - return gn_success; - } - - int gn_config_get_npts(size_t *npts, gn_config *c) - { - if (!(*c)) - { - printf("config struct is NULL\n"); - return gn_failure; - } - *npts = (*c)->npts; - return gn_success; - } - - int gn_config_set_sample_rate(gn::real_t sample_rate, gn_config *c) - { - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->sample_rate = sample_rate; - return gn_success; - } - - int gn_config_get_sample_rate(double *sample_rate, gn_config *c) - { - if (!(*c)) - { - printf("config struct is NULL\n"); - return gn_failure; - } - *sample_rate = (*c)->sample_rate; - return gn_success; - } - - int gn_config_set_data_rate(gn::real_t data_rate, gn_config *c) - { - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->data_rate = data_rate; - return gn_success; - } - - int gn_config_set_shift_freq(gn::real_t shift_freq, gn_config *c) - { - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->shift_freq = shift_freq; - return gn_success; - } - - int gn_config_set_num_tones(size_t num_tones, gn_config *c) - { - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->num_tones = num_tones; - return gn_success; - } - - int gn_config_set_tone_freq(gn::real_t *tone_freq, gn_config *c) - { - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->tone_freq = tone_freq; - return gn_success; - } - - int gn_config_set_tone_ampl(gn::real_t *tone_ampl, gn_config *c) - { - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->tone_ampl = tone_ampl; - return gn_success; - } - - int gn_config_set_tone_phase(gn::real_t *tone_phase, gn_config *c) - { - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->tone_phase = tone_phase; - return gn_success; - } - - int gn_config_set_fsr(gn::real_t fsr, gn_config *c) - { - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->fsr = fsr; - return gn_success; - } - - int gn_config_set_qres(int qres, gn_config *c) - { - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->qres = qres; - return gn_success; - } - - int gn_config_set_noise_rms(gn::real_t noise_rms, gn_config *c) - { - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->noise_rms = noise_rms; - return gn_success; - } - - int gn_config_set_code_format(GnCodeFormat code_format, gn_config *c) - { - if (!((code_format == GnCodeFormatOffsetBinary) || (code_format == GnCodeFormatTwosComplement))) - { - printf("ERROR: Invalid selection of code format\n"); - return gn_failure; - } - - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->code_format = code_format; - return gn_success; - } - - int gn_config_set_nfft(size_t nfft, gn_config *c) - { - if (((*c)->nfft) > ((*c)->npts)) - { - printf("ERROR: FFT order cannot be greater than the number of sample points\n"); - return gn_failure; - } - - double rem = 1.0*(((*c)->npts)%((*c)->nfft)); - if (rem > 0) - { - printf("ERROR: FFT order has to be a multiple of the number of sample points\n"); - return gn_failure; - } - - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->nfft = nfft; - (*c)->fft_navg = (*c)->npts/(*c)->nfft; - return gn_success; - } - - int gn_config_get_nfft(size_t *nfft, gn_config *c) - { - if (!(*c)) - { - printf("here - config struct is NULL\n"); - return gn_failure; - } - *nfft = (*c)->nfft; - return gn_success; - } - - int gn_config_set_fft_navg(size_t fft_navg, gn_config *c) - { - if (((*c)->fft_navg) > ((*c)->npts)) - { - printf("ERROR: Number of FFT averages cannot be greater than the number of sample points\n"); - return gn_failure; - } - - double rem = 1.0*(((*c)->npts)%((*c)->fft_navg)); - if (rem > 0) - { - printf("ERROR: Number of FFT averages has to be a multiple of the number of sample points\n"); - return gn_failure; - } - - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->fft_navg = fft_navg; - (*c)->nfft = (*c)->npts/(*c)->fft_navg; - return gn_success; - } - - int gn_config_set_win(GnWindow win, gn_config *c) - { - if (!((win == GnWindowBlackmanHarris) || (win == GnWindowHann) || (win == GnWindowNoWindow))) - { - printf("ERROR: Invalid selection of window function\n"); - return gn_failure; - } - - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->win = win; - return gn_success; - } - - int gn_config_set_ssb_fund(int ssb_fund, gn_config *c) - { - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->ssb_fund = ssb_fund; - return gn_success; - } - - int gn_config_set_ssb_rest(int ssb_rest, gn_config *c) - { - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->ssb_rest = ssb_rest; - return gn_success; - } - - int gn_config_set_max_harm_order(int max_harm_order, gn_config *c) - { - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->max_harm_order = max_harm_order; - return gn_success; - } - - int gn_config_set_dnla_signal_type(GnDnlSignal dnla_signal_type, gn_config *c) - { - if (!((dnla_signal_type == GnDnlSignalRamp) || (dnla_signal_type == GnDnlSignalTone))) - { - printf("ERROR: Invalid selection of DNL analysis signal type\n"); - return gn_failure; - } - - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->dnla_signal_type = dnla_signal_type; - return gn_success; - } - - int gn_config_set_inla_fit(GnInlLineFit inla_fit, gn_config *c) - { - if (!((inla_fit == GnInlLineFitBestFit) || (inla_fit == GnInlLineFitEndFit) || (inla_fit == GnInlLineFitNoFit))) - { - printf("ERROR: Invalid selection of INL line fit\n"); - return gn_failure; - } - - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->inla_fit = inla_fit; - return gn_success; - } - - int gn_config_set_ramp_start(double ramp_start, gn_config *c) - { - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->ramp_start = ramp_start; - return gn_success; - } - - int gn_config_set_ramp_stop(double ramp_stop, gn_config *c) - { - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->ramp_stop = ramp_stop; - return gn_success; - } - - int gn_config_get_code_density_size(size_t *code_density_size, gn_config *c) - { - if (!(*c)) - { - printf("config struct is NULL\n"); - return gn_failure; - } - *code_density_size = (*c)->_code_density_size; - return gn_success; - } - - int gn_config_gen_tone(tone_type ttype, size_t npts, gn::real_t sample_rate, size_t num_tones, gn::real_t *tone_freq, gn::real_t *tone_ampl, gn::real_t *tone_phase, gn_config *c) - { - if (!((ttype == REAL_COSINE) || (ttype == REAL_SINE) || (ttype == COMPLEX_EXP))) - { - printf("ERROR: Invalid selection of waveform type for tone generation\n"); - return gn_failure; - } - - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->ttype = ttype; - (*c)->npts = npts; - (*c)->sample_rate = sample_rate; - (*c)->num_tones = num_tones; - (*c)->tone_freq = tone_freq; - (*c)->tone_ampl = tone_ampl; - (*c)->tone_phase = tone_phase; - - return gn_success; - } - - int gn_config_gen_ramp(size_t npts, double ramp_start, double ramp_stop, gn_config *c) - { - if (ramp_stop < ramp_start) - { - printf("ERROR: ramp stop value cannot be smaller than ramp start value for ramp generation\n"); - return gn_failure; - } - - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->npts = npts; - (*c)->ramp_start = ramp_start; - (*c)->ramp_stop = ramp_stop; - (*c)->noise_rms = 0.0; - - return gn_success; - } - - int gn_config_quantize(size_t npts, gn::real_t fsr, int qres, gn::real_t noise_rms, gn_config *c) - { - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->npts = npts; - (*c)->fsr = fsr; - (*c)->qres = qres; - (*c)->noise_rms = noise_rms; - (*c)->code_format = GnCodeFormatTwosComplement; - - return gn_success; - } - - int gn_config_histz_nla(size_t npts, int qres, gn_config *c) - { - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - (*c)->npts = npts; - (*c)->qres = qres; - (*c)->code_format = GnCodeFormatTwosComplement; - (*c)->inla_fit = GnInlLineFitBestFit; - - return gn_success; - } - - int gn_config_fftz(size_t npts, int qres, size_t fft_navg, size_t nfft, GnWindow win, gn_config *c) - { - if (npts != (fft_navg*nfft)) - { - printf("ERROR: Number of samples points in the waveform has to equal FFT order times number of FFT averages\n"); - return gn_failure; - } - - if (!((win == GnWindowBlackmanHarris) || (win == GnWindowHann) || (win == GnWindowNoWindow))) - { - printf("ERROR: Invalid selection of window function\n"); - return gn_failure; - } - - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - - (*c)->npts = npts; - (*c)->qres = qres; - (*c)->fft_navg = fft_navg; - (*c)->nfft = nfft; - (*c)->win = win; - (*c)->code_format = GnCodeFormatTwosComplement; - - return gn_success; - } - - int gn_config_fa_auto(uint8_t ssb_width, gn_config *c) - { - int err_code; - - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - - if ((*c)->sample_rate <= 0) { - printf("ERROR: Sample rate must be set before configuring Fourier analysis\n"); - return gn_failure; - } - - (*c)->obj_key = (char *)calloc(3, sizeof(char)); - strcpy((*c)->obj_key, "fa"); - (*c)->comp_key = (char *)calloc(2, sizeof(char)); - strcpy((*c)->comp_key, "A"); - - (*c)->ssb_fund = ssb_width; - (*c)->ssb_rest = 0; - (*c)->max_harm_order = 3; - (*c)->axis_type = GnFreqAxisTypeDcCenter; - - // configure object key for Fourier analysis - err_code = gn_fa_create((*c)->obj_key); - - // configure component key for Fourier analysis - err_code += gn_fa_max_tone((*c)->obj_key, (*c)->comp_key, GnFACompTagSignal, (*c)->ssb_fund); - - // configure harmonic order for Fourier analysis - err_code += gn_fa_hd((*c)->obj_key, (*c)->max_harm_order); - - // configure single-side bins for Fourier analysis - err_code += gn_fa_ssb((*c)->obj_key, GnFASsbDefault, (*c)->ssb_rest); - err_code += gn_fa_ssb((*c)->obj_key, GnFASsbDC, -1); - err_code += gn_fa_ssb((*c)->obj_key, GnFASsbSignal, -1); - err_code += gn_fa_ssb((*c)->obj_key, GnFASsbWO, -1); - - // configure sample-rate, data-rate, shift frequency, and converter offset - err_code += gn_fa_fsample((*c)->obj_key, (*c)->sample_rate); - err_code += gn_fa_fdata((*c)->obj_key, (*c)->sample_rate); - err_code += gn_fa_fshift((*c)->obj_key, 0.0); - err_code += gn_fa_conv_offset((*c)->obj_key, false); - - return (err_code); - } - - - int gn_config_fa(gn::real_t fixed_tone_freq, gn_config *c) - { - int err_code; - - if (!(*c)) - { - gn_config c_p; - c_p = (gn_config)calloc(1, sizeof(*c_p)); - if (!(c_p)) - { - printf("insufficient memory\n"); - return ENOMEM; - } - else - *c = c_p; - } - - if ((*c)->sample_rate <= 0) { - printf("ERROR: Sample rate must be set before configuring Fourier analysis\n"); - return gn_failure; - } - - (*c)->obj_key = (char *)calloc(3, sizeof(char)); - strcpy((*c)->obj_key, "fa"); - (*c)->comp_key = (char *)calloc(2, sizeof(char)); - strcpy((*c)->comp_key, "A"); - - (*c)->ssb_fund = 120; - (*c)->ssb_rest = 0; - (*c)->max_harm_order = 3; - (*c)->axis_type = GnFreqAxisTypeDcCenter; - - // configure object key for Fourier analysis - err_code = gn_fa_create((*c)->obj_key); - - // configure component key for Fourier analysis - err_code += gn_fa_fixed_tone((*c)->obj_key, (*c)->comp_key, GnFACompTagSignal, fixed_tone_freq, (*c)->ssb_fund); - - // configure harmonic order for Fourier analysis - err_code += gn_fa_hd((*c)->obj_key, (*c)->max_harm_order); - - // configure single-side bins for Fourier analysis - err_code += gn_fa_ssb((*c)->obj_key, GnFASsbDefault, (*c)->ssb_rest); - err_code += gn_fa_ssb((*c)->obj_key, GnFASsbDC, -1); - err_code += gn_fa_ssb((*c)->obj_key, GnFASsbSignal, -1); - err_code += gn_fa_ssb((*c)->obj_key, GnFASsbWO, -1); - - // configure sample-rate, data-rate, shift frequency, and converter offset - err_code += gn_fa_fsample((*c)->obj_key, (*c)->sample_rate); - err_code += gn_fa_fdata((*c)->obj_key, (*c)->sample_rate); - err_code += gn_fa_fshift((*c)->obj_key, 0.0); - err_code += gn_fa_conv_offset((*c)->obj_key, false); - - return (err_code); - } - - // waveform generation - int gn_gen_ramp(gn::real_t **out, gn_config *c) - { - int err_code; - gn::real_t *awf = (gn::real_t *)calloc((*c)->npts, sizeof(gn::real_t)); - err_code = gn_ramp(awf, (*c)->npts, (*c)->ramp_start, (*c)->ramp_stop, (*c)->noise_rms); - *out = awf; - - return err_code; - } - - int gn_gen_real_tone(gn::real_t **out, gn_config *c) - { - int err_code = 0; - gn::real_t *awf = (gn::real_t *)calloc((*c)->npts, sizeof(gn::real_t)); - - for (size_t i = 0; i < (*c)->num_tones; i++) - { - gn::real_t *tmp = (gn::real_t *)calloc((*c)->npts, sizeof(gn::real_t)); - if ((*c)->ttype == REAL_COSINE) - err_code = gn_cos(tmp, (*c)->npts, (*c)->sample_rate, (*c)->tone_ampl[i], (*c)->tone_freq[i], (*c)->tone_phase[i], 0, 0); - else if ((*c)->ttype == REAL_SINE) - err_code = gn_sin(tmp, (*c)->npts, (*c)->sample_rate, (*c)->tone_ampl[i], (*c)->tone_freq[i], (*c)->tone_phase[i], 0, 0); - if (!err_code) - { - for (size_t j = 0; j < (*c)->npts; j++) - awf[j] = awf[j] + tmp[j]; - } - } - *out = awf; - - return err_code; - } - - int gn_gen_complex_tone(gn::real_t **outi, gn::real_t **outq, gn_config *c) - { - int err_code = 0; - gn::real_t *awfi = (gn::real_t *)calloc((*c)->npts, sizeof(gn::real_t)); - gn::real_t *awfq = (gn::real_t *)calloc((*c)->npts, sizeof(gn::real_t)); - - for (size_t i = 0; i < (*c)->num_tones; i++) { - gn::real_t *tmp = (gn::real_t *)calloc((*c)->npts, sizeof(gn::real_t)); - err_code = gn_cos(tmp, (*c)->npts, (*c)->sample_rate, (*c)->tone_ampl[i], (*c)->tone_freq[i], (*c)->tone_phase[i], 0, 0); - if (!err_code) - { - for (size_t j = 0; j < (*c)->npts; j++) - awfi[j] = awfi[j] + tmp[j]; - } - tmp = (gn::real_t *)calloc((*c)->npts, sizeof(gn::real_t)); - err_code = gn_sin(tmp, (*c)->npts, (*c)->sample_rate, (*c)->tone_ampl[i], (*c)->tone_freq[i], (*c)->tone_phase[i], 0, 0); - if (!err_code) - { - for (size_t j = 0; j < (*c)->npts; j++) - awfq[j] = awfq[j] + tmp[j]; - } - } - *outi = awfi; - *outq = awfq; - - return err_code; - } - - // processing - int gn_quantize(int32_t **out, const gn::real_t *in, gn_config *c) - { - int err_code; - int32_t *qwf = (int32_t *)calloc((*c)->npts, sizeof(int32_t)); - - err_code = gn_quantize32(qwf, (*c)->npts, in, (*c)->npts, (*c)->fsr, (*c)->qres, (*c)->noise_rms, (*c)->code_format); - *out = qwf; - - return err_code; - } - - int gn_fftz(gn::real_t **out, const int32_t *in_i, const int32_t *in_q, gn_config *c) - { - int err_code; - gn::real_t *fft_of_in = (gn::real_t *)calloc(2*(*c)->nfft, sizeof(gn::real_t)); - - err_code = gn_fft32(fft_of_in, 2*(*c)->nfft, in_i, (*c)->npts, in_q, (*c)->npts, (*c)->qres, (*c)->fft_navg, (*c)->nfft, (*c)->win, (*c)->code_format); - *out = fft_of_in; - - return err_code; - } - - int gn_histz(uint64_t **hist, size_t *hist_len, const int32_t *qwf, gn_config *c) - { - int err_code; - uint64_t *out = NULL; - - err_code = gn_code_density_size(&((*c)->_code_density_size), (*c)->qres, (*c)->code_format); - out = (uint64_t *)calloc((*c)->_code_density_size, sizeof(uint64_t)); - err_code += gn_hist32(out, (*c)->_code_density_size, qwf, (*c)->npts, (*c)->qres, (*c)->code_format, false); - *hist = out; - *hist_len = (*c)->_code_density_size; - - return err_code; - } - - int gn_dnlz(double **dnl, size_t *dnl_len, const uint64_t *hist, gn_config *c) - { - int err_code; - double *out = NULL; - - err_code = gn_code_density_size(&((*c)->_code_density_size), (*c)->qres, (*c)->code_format); - out = (double *)calloc((*c)->_code_density_size, sizeof(double)); - err_code = gn_dnl(out, (*c)->_code_density_size, hist, (*c)->_code_density_size, (*c)->dnla_signal_type); - *dnl = out; - *dnl_len = (*c)->_code_density_size; - - return err_code; - } - - int gn_inlz(double **inl, size_t *inl_len, const double *dnl, gn_config *c) - { - int err_code; - double *out = NULL; - - err_code = gn_code_density_size(&((*c)->_code_density_size), (*c)->qres, (*c)->code_format); - out = (double *)calloc((*c)->_code_density_size, sizeof(double)); - err_code = gn_inl(out, (*c)->_code_density_size, dnl, (*c)->_code_density_size, (*c)->inla_fit); - *inl = out; - *inl_len = (*c)->_code_density_size; - - return err_code; - } - - // Waveform/Histogram/DNL/INL/Fourier Analysis - int gn_get_wfa_results(char ***rkeys, gn::real_t **rvalues, size_t *results_size, const int32_t *qwf, gn_config *c) - { - int err_code = 0; - - // get results size - err_code = gn_analysis_results_size(&((*c)->_wfa_results_size), GnAnalysisTypeWaveform); - - // allocate memory for result keys and values - (*c)->_wfa_result_keys = (char **)calloc(((*c)->_wfa_results_size), sizeof(char*)); - (*c)->_wfa_result_values = (gn::real_t *)calloc(((*c)->_wfa_results_size), sizeof(gn::real_t)); - - // get result key sizes - (*c)->_wfa_result_key_sizes = (size_t *)calloc(((*c)->_wfa_results_size), sizeof(size_t)); - err_code += gn_analysis_results_key_sizes((*c)->_wfa_result_key_sizes, (*c)->_wfa_results_size, GnAnalysisTypeWaveform); - - // allocate memory for each result key - for (size_t i = 0; i < (*c)->_wfa_results_size; ++i) - (*c)->_wfa_result_keys[i] = (char *)calloc((*c)->_wfa_result_key_sizes[i], sizeof(char)); - - // execute analysis - err_code += gn_wf_analysis32((*c)->_wfa_result_keys, (*c)->_wfa_results_size, (*c)->_wfa_result_values, (*c)->_wfa_results_size, qwf, (*c)->npts); - - // copy keys - *rkeys = (char **)calloc(((*c)->_wfa_results_size), sizeof(char*)); - for (size_t i = 0; i < (*c)->_wfa_results_size; ++i) - (*rkeys)[i] = (char *)calloc((*c)->_wfa_result_key_sizes[i], sizeof(char)); - - // copy values - *rvalues = (gn::real_t *)calloc(((*c)->_wfa_results_size), sizeof(gn::real_t)); - for (size_t i = 0; i < (*c)->_wfa_results_size; ++i) - { - strcpy((*rkeys)[i], (*c)->_wfa_result_keys[i]); - (*rvalues)[i] = (*c)->_wfa_result_values[i]; - } - *results_size = (*c)->_wfa_results_size; - - return(err_code); - } - - int gn_get_ha_results(char ***rkeys, gn::real_t **rvalues, size_t *results_size, const uint64_t *hist, gn_config *c) - { - int err_code = 0; - - // get results size - err_code = gn_analysis_results_size(&((*c)->_hist_results_size), GnAnalysisTypeHistogram); - - // allocate memory for result keys and values - (*c)->_hist_result_keys = (char **)calloc(((*c)->_hist_results_size), sizeof(char*)); - (*c)->_hist_result_values = (gn::real_t *)calloc(((*c)->_hist_results_size), sizeof(gn::real_t)); - - // get result key sizes - (*c)->_hist_result_key_sizes = (size_t *)calloc(((*c)->_hist_results_size), sizeof(size_t)); - err_code += gn_analysis_results_key_sizes((*c)->_hist_result_key_sizes, (*c)->_hist_results_size, GnAnalysisTypeHistogram); - - // allocate memory for each result key - for (size_t i = 0; i < (*c)->_hist_results_size; ++i) - (*c)->_hist_result_keys[i] = (char *)calloc((*c)->_hist_result_key_sizes[i], sizeof(char)); - - // execute analysis - err_code += gn_hist_analysis((*c)->_hist_result_keys, (*c)->_hist_results_size, (*c)->_hist_result_values, (*c)->_hist_results_size, hist, (*c)->_code_density_size); - - // copy keys - *rkeys = (char **)calloc(((*c)->_hist_results_size), sizeof(char*)); - for (size_t i = 0; i < (*c)->_hist_results_size; ++i) - (*rkeys)[i] = (char *)calloc((*c)->_hist_result_key_sizes[i], sizeof(char)); - - // copy values - *rvalues = (gn::real_t *)calloc(((*c)->_hist_results_size), sizeof(gn::real_t)); - for (size_t i = 0; i < (*c)->_hist_results_size; ++i) - { - strcpy((*rkeys)[i], (*c)->_hist_result_keys[i]); - (*rvalues)[i] = (*c)->_hist_result_values[i]; - } - *results_size = (*c)->_hist_results_size; - - return(err_code); - } - - int gn_get_dnla_results(char ***rkeys, gn::real_t **rvalues, size_t *results_size, const gn::real_t *dnl, gn_config *c) - { - int err_code; - - // get results size - err_code = gn_analysis_results_size(&((*c)->_dnl_results_size), GnAnalysisTypeDNL); - - // allocate memory for result keys and values - (*c)->_dnl_result_keys = (char **)calloc(((*c)->_dnl_results_size), sizeof(char*)); - (*c)->_dnl_result_values = (gn::real_t *)calloc(((*c)->_dnl_results_size), sizeof(gn::real_t)); - - // get result key sizes - (*c)->_dnl_result_key_sizes = (size_t *)calloc(((*c)->_dnl_results_size), sizeof(size_t)); - err_code += gn_analysis_results_key_sizes((*c)->_dnl_result_key_sizes, (*c)->_dnl_results_size, GnAnalysisTypeDNL); - - // allocate memory for each result key - for (size_t i = 0; i < (*c)->_dnl_results_size; ++i) - (*c)->_dnl_result_keys[i] = (char *)calloc((*c)->_dnl_result_key_sizes[i], sizeof(char)); - - // execute analysis - err_code += gn_dnl_analysis((*c)->_dnl_result_keys, (*c)->_dnl_results_size, (*c)->_dnl_result_values, (*c)->_dnl_results_size, dnl, (*c)->_code_density_size); - - // copy keys - *rkeys = (char **)calloc(((*c)->_dnl_results_size), sizeof(char*)); - for (size_t i = 0; i < (*c)->_dnl_results_size; ++i) - (*rkeys)[i] = (char *)calloc((*c)->_dnl_result_key_sizes[i], sizeof(char)); - - // copy values - *rvalues = (gn::real_t *)calloc(((*c)->_dnl_results_size), sizeof(gn::real_t)); - for (size_t i = 0; i < (*c)->_dnl_results_size; ++i) - { - strcpy((*rkeys)[i], (*c)->_dnl_result_keys[i]); - (*rvalues)[i] = (*c)->_dnl_result_values[i]; - } - *results_size = (*c)->_dnl_results_size; - - return(err_code); - } - - int gn_get_inla_results(char ***rkeys, gn::real_t **rvalues, size_t *results_size, const gn::real_t *inl, gn_config *c) - { - int err_code; - - // get results size - err_code = gn_analysis_results_size(&((*c)->_inl_results_size), GnAnalysisTypeINL); - - // allocate memory for result keys and values - (*c)->_inl_result_keys = (char **)calloc(((*c)->_inl_results_size), sizeof(char*)); - (*c)->_inl_result_values = (gn::real_t *)calloc(((*c)->_inl_results_size), sizeof(gn::real_t)); - - // get result key sizes - (*c)->_inl_result_key_sizes = (size_t *)calloc(((*c)->_inl_results_size), sizeof(size_t)); - err_code += gn_analysis_results_key_sizes((*c)->_inl_result_key_sizes, (*c)->_inl_results_size, GnAnalysisTypeINL); - - // allocate memory for each result key - for (size_t i = 0; i < (*c)->_inl_results_size; ++i) - (*c)->_inl_result_keys[i] = (char *)calloc((*c)->_inl_result_key_sizes[i], sizeof(char)); - - // execute analysis - err_code += gn_inl_analysis((*c)->_inl_result_keys, (*c)->_inl_results_size, (*c)->_inl_result_values, (*c)->_inl_results_size, inl, (*c)->_code_density_size); - - // copy keys - *rkeys = (char **)calloc(((*c)->_inl_results_size), sizeof(char*)); - for (size_t i = 0; i < (*c)->_inl_results_size; ++i) - (*rkeys)[i] = (char *)calloc((*c)->_inl_result_key_sizes[i], sizeof(char)); - - // copy values - *rvalues = (gn::real_t *)calloc(((*c)->_inl_results_size), sizeof(gn::real_t)); - for (size_t i = 0; i < (*c)->_inl_results_size; ++i) - { - strcpy((*rkeys)[i], (*c)->_inl_result_keys[i]); - (*rvalues)[i] = (*c)->_inl_result_values[i]; - } - *results_size = (*c)->_inl_results_size; - - return(err_code); - } - - int gn_get_fa_single_result(gn::real_t *rvalue, const char *metric_name, gn::real_t *fft_ilv, gn_config *c) - { - int err_code; - size_t i; - bool metric_found = false; - size_t results_size; - char **rkeys; - double *rvalues; - - // compute all results - err_code = gn_get_fa_results(&rkeys, &rvalues, &results_size, fft_ilv, &(*c)); - for (i = 0; i < results_size; i++) - { - if (!strcmp(metric_name, rkeys[i])) - { - metric_found = true; - break; - } - } - if (!metric_found) - { - printf("ERROR: Invalid selection of metric\n"); - return gn_failure; - } - *rvalue = rvalues[i]; - - return err_code; - } - - int gn_get_fa_results(char ***rkeys, gn::real_t **rvalues, size_t *results_size, gn::real_t *fft_ilv, gn_config *c) - { - int err_code = 0; - size_t *result_key_sizes; - - // get results size - err_code = gn_fft_analysis_results_size(results_size, (*c)->obj_key, 2*(*c)->nfft, (*c)->nfft); - - // allocate memory for result keys and values - *rkeys = (char **)calloc(*results_size, sizeof(char*)); - *rvalues = (gn::real_t *)calloc(*results_size, sizeof(gn::real_t)); - - // get result key sizes - result_key_sizes = (size_t *)calloc(*results_size, sizeof(size_t)); - err_code += gn_fft_analysis_results_key_sizes(result_key_sizes, *results_size, (*c)->obj_key, 2*(*c)->nfft, (*c)->nfft); - - // allocate memory for each result key - for (size_t i = 0; i < *results_size; ++i) - (*rkeys)[i] = (char *)calloc(result_key_sizes[i], sizeof(char)); - - // execute analysis - err_code += gn_fft_analysis(*rkeys, *results_size, *rvalues, *results_size, (*c)->obj_key, fft_ilv, 2*(*c)->nfft, (*c)->nfft, (*c)->axis_type); - - return (err_code); - } +int gn_config_free(gn_config *c) { + if ((*c)->obj_key) { + gn_mgr_remove((*c)->obj_key); + free((*c)->obj_key); + } + if ((*c)->comp_key) { + gn_fa_remove_comp((*c)->obj_key, (*c)->comp_key); + free((*c)->comp_key); + } + if (((*c)->_fa_results_size) > 0) { + for (size_t i = 0; i < (*c)->_fa_results_size; i++) + free((*c)->_fa_result_keys[i]); + free((*c)->_fa_result_keys); + free((*c)->_fa_result_key_sizes); + free((*c)->_fa_result_values); + } + if (((*c)->_wfa_results_size) > 0) { + for (size_t i = 0; i < (*c)->_wfa_results_size; i++) + free((*c)->_wfa_result_keys[i]); + free((*c)->_wfa_result_keys); + free((*c)->_wfa_result_key_sizes); + free((*c)->_wfa_result_values); + } + if (((*c)->_hist_results_size) > 0) { + for (size_t i = 0; i < (*c)->_hist_results_size; i++) + free((*c)->_hist_result_keys[i]); + free((*c)->_hist_result_keys); + free((*c)->_hist_result_key_sizes); + free((*c)->_hist_result_values); + } + if (((*c)->_dnl_results_size) > 0) { + for (size_t i = 0; i < (*c)->_dnl_results_size; i++) + free((*c)->_dnl_result_keys[i]); + free((*c)->_dnl_result_keys); + free((*c)->_dnl_result_key_sizes); + free((*c)->_dnl_result_values); + } + if (((*c)->_inl_results_size) > 0) { + for (size_t i = 0; i < (*c)->_inl_results_size; i++) + free((*c)->_inl_result_keys[i]); + free((*c)->_inl_result_keys); + free((*c)->_inl_result_key_sizes); + free((*c)->_inl_result_values); + } + free(*c); + + return gn_success; +} + +int gn_config_set_ttype(tone_type ttype, gn_config *c) { + if (!((ttype == REAL_COSINE) || (ttype == REAL_SINE) || + (ttype == COMPLEX_EXP))) { + printf("ERROR: Invalid selection of ttype for tone generation\n"); + return gn_failure; + } + + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->ttype = ttype; + + return gn_success; +} + +int gn_config_set_npts(size_t npts, gn_config *c) { + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->npts = npts; + return gn_success; +} + +int gn_config_get_npts(size_t *npts, gn_config *c) { + if (!(*c)) { + printf("config struct is NULL\n"); + return gn_failure; + } + *npts = (*c)->npts; + return gn_success; +} + +int gn_config_set_sample_rate(gn::real_t sample_rate, gn_config *c) { + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->sample_rate = sample_rate; + return gn_success; +} + +int gn_config_get_sample_rate(double *sample_rate, gn_config *c) { + if (!(*c)) { + printf("config struct is NULL\n"); + return gn_failure; + } + *sample_rate = (*c)->sample_rate; + return gn_success; +} + +int gn_config_set_data_rate(gn::real_t data_rate, gn_config *c) { + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->data_rate = data_rate; + return gn_success; +} + +int gn_config_set_shift_freq(gn::real_t shift_freq, gn_config *c) { + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->shift_freq = shift_freq; + return gn_success; +} + +int gn_config_set_num_tones(size_t num_tones, gn_config *c) { + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->num_tones = num_tones; + return gn_success; +} + +int gn_config_set_tone_freq(gn::real_t *tone_freq, gn_config *c) { + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->tone_freq = tone_freq; + return gn_success; +} + +int gn_config_set_tone_ampl(gn::real_t *tone_ampl, gn_config *c) { + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->tone_ampl = tone_ampl; + return gn_success; +} + +int gn_config_set_tone_phase(gn::real_t *tone_phase, gn_config *c) { + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->tone_phase = tone_phase; + return gn_success; +} + +int gn_config_set_fsr(gn::real_t fsr, gn_config *c) { + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->fsr = fsr; + return gn_success; +} + +int gn_config_set_qres(int qres, gn_config *c) { + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->qres = qres; + return gn_success; +} + +int gn_config_set_noise_rms(gn::real_t noise_rms, gn_config *c) { + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->noise_rms = noise_rms; + return gn_success; +} + +int gn_config_set_code_format(GnCodeFormat code_format, gn_config *c) { + if (!((code_format == GnCodeFormatOffsetBinary) || + (code_format == GnCodeFormatTwosComplement))) { + printf("ERROR: Invalid selection of code format\n"); + return gn_failure; + } + + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->code_format = code_format; + return gn_success; +} + +int gn_config_set_nfft(size_t nfft, gn_config *c) { + if (((*c)->nfft) > ((*c)->npts)) { + printf("ERROR: FFT order cannot be greater than the number of sample points\n"); + return gn_failure; + } + + double rem = 1.0 * (((*c)->npts) % ((*c)->nfft)); + if (rem > 0) { + printf("ERROR: FFT order has to be a multiple of the number of sample points\n"); + return gn_failure; + } + + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->nfft = nfft; + (*c)->fft_navg = (*c)->npts / (*c)->nfft; + return gn_success; +} + +int gn_config_get_nfft(size_t *nfft, gn_config *c) { + if (!(*c)) { + printf("here - config struct is NULL\n"); + return gn_failure; + } + *nfft = (*c)->nfft; + return gn_success; +} + +int gn_config_set_fft_navg(size_t fft_navg, gn_config *c) { + if (((*c)->fft_navg) > ((*c)->npts)) { + printf("ERROR: Number of FFT averages cannot be greater than the number of sample points\n"); + return gn_failure; + } + + double rem = 1.0 * (((*c)->npts) % ((*c)->fft_navg)); + if (rem > 0) { + printf("ERROR: Number of FFT averages has to be a multiple of the number of sample points\n"); + return gn_failure; + } + + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->fft_navg = fft_navg; + (*c)->nfft = (*c)->npts / (*c)->fft_navg; + return gn_success; +} + +int gn_config_set_win(GnWindow win, gn_config *c) { + if (!((win == GnWindowBlackmanHarris) || (win == GnWindowHann) || + (win == GnWindowNoWindow))) { + printf("ERROR: Invalid selection of window function\n"); + return gn_failure; + } + + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->win = win; + return gn_success; +} + +int gn_config_set_ssb_fund(int ssb_fund, gn_config *c) { + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->ssb_fund = ssb_fund; + return gn_success; +} + +int gn_config_set_ssb_rest(int ssb_rest, gn_config *c) { + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->ssb_rest = ssb_rest; + return gn_success; +} + +int gn_config_set_max_harm_order(int max_harm_order, gn_config *c) { + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->max_harm_order = max_harm_order; + return gn_success; +} + +int gn_config_set_dnla_signal_type(GnDnlSignal dnla_signal_type, gn_config *c) { + if (!((dnla_signal_type == GnDnlSignalRamp) || + (dnla_signal_type == GnDnlSignalTone))) { + printf("ERROR: Invalid selection of DNL analysis signal type\n"); + return gn_failure; + } + + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->dnla_signal_type = dnla_signal_type; + return gn_success; +} + +int gn_config_set_inla_fit(GnInlLineFit inla_fit, gn_config *c) { + if (!((inla_fit == GnInlLineFitBestFit) || + (inla_fit == GnInlLineFitEndFit) || + (inla_fit == GnInlLineFitNoFit))) { + printf("ERROR: Invalid selection of INL line fit\n"); + return gn_failure; + } + + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->inla_fit = inla_fit; + return gn_success; +} + +int gn_config_set_ramp_start(double ramp_start, gn_config *c) { + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->ramp_start = ramp_start; + return gn_success; +} + +int gn_config_set_ramp_stop(double ramp_stop, gn_config *c) { + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->ramp_stop = ramp_stop; + return gn_success; +} + +int gn_config_get_code_density_size(size_t *code_density_size, gn_config *c) { + if (!(*c)) { + printf("config struct is NULL\n"); + return gn_failure; + } + *code_density_size = (*c)->_code_density_size; + return gn_success; +} + +int gn_config_gen_tone(tone_type ttype, size_t npts, gn::real_t sample_rate, + size_t num_tones, gn::real_t *tone_freq, + gn::real_t *tone_ampl, gn::real_t *tone_phase, + gn_config *c) { + if (!((ttype == REAL_COSINE) || (ttype == REAL_SINE) || + (ttype == COMPLEX_EXP))) { + printf("ERROR: Invalid selection of waveform type for tone generation\n"); + return gn_failure; + } + + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->ttype = ttype; + (*c)->npts = npts; + (*c)->sample_rate = sample_rate; + (*c)->num_tones = num_tones; + (*c)->tone_freq = tone_freq; + (*c)->tone_ampl = tone_ampl; + (*c)->tone_phase = tone_phase; + + return gn_success; +} + +int gn_config_gen_ramp(size_t npts, double ramp_start, double ramp_stop, + gn_config *c) { + if (ramp_stop < ramp_start) { + printf("ERROR: ramp stop value cannot be smaller than ramp start value for ramp generation\n"); + return gn_failure; + } + + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->npts = npts; + (*c)->ramp_start = ramp_start; + (*c)->ramp_stop = ramp_stop; + (*c)->noise_rms = 0.0; + + return gn_success; +} + +int gn_config_quantize(size_t npts, gn::real_t fsr, int qres, + gn::real_t noise_rms, gn_config *c) { + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->npts = npts; + (*c)->fsr = fsr; + (*c)->qres = qres; + (*c)->noise_rms = noise_rms; + (*c)->code_format = GnCodeFormatTwosComplement; + + return gn_success; +} + +int gn_config_histz_nla(size_t npts, int qres, gn_config *c) { + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + (*c)->npts = npts; + (*c)->qres = qres; + (*c)->code_format = GnCodeFormatTwosComplement; + (*c)->inla_fit = GnInlLineFitBestFit; + + return gn_success; +} + +int gn_config_fftz(size_t npts, int qres, size_t fft_navg, size_t nfft, + GnWindow win, gn_config *c) { + if (npts != (fft_navg * nfft)) { + printf("ERROR: Number of samples points in the waveform has to equal FFT order times number of FFT averages\n"); + return gn_failure; + } + + if (!((win == GnWindowBlackmanHarris) || (win == GnWindowHann) || + (win == GnWindowNoWindow))) { + printf("ERROR: Invalid selection of window function\n"); + return gn_failure; + } + + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + + (*c)->npts = npts; + (*c)->qres = qres; + (*c)->fft_navg = fft_navg; + (*c)->nfft = nfft; + (*c)->win = win; + (*c)->code_format = GnCodeFormatTwosComplement; + + return gn_success; +} + +int gn_config_fa_auto(uint8_t ssb_width, gn_config *c) { + int err_code; + + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + + if ((*c)->sample_rate <= 0) { + printf("ERROR: Sample rate must be set before configuring Fourier analysis\n"); + return gn_failure; + } + + (*c)->obj_key = (char *)calloc(3, sizeof(char)); + strcpy((*c)->obj_key, "fa"); + (*c)->comp_key = (char *)calloc(2, sizeof(char)); + strcpy((*c)->comp_key, "A"); + + (*c)->ssb_fund = ssb_width; + (*c)->ssb_rest = 0; + (*c)->max_harm_order = 3; + (*c)->axis_type = GnFreqAxisTypeDcCenter; + + // configure object key for Fourier analysis + err_code = gn_fa_create((*c)->obj_key); + + // configure component key for Fourier analysis + err_code += gn_fa_max_tone((*c)->obj_key, (*c)->comp_key, + GnFACompTagSignal, (*c)->ssb_fund); + + // configure harmonic order for Fourier analysis + err_code += gn_fa_hd((*c)->obj_key, (*c)->max_harm_order); + + // configure single-side bins for Fourier analysis + err_code += gn_fa_ssb((*c)->obj_key, GnFASsbDefault, (*c)->ssb_rest); + err_code += gn_fa_ssb((*c)->obj_key, GnFASsbDC, -1); + err_code += gn_fa_ssb((*c)->obj_key, GnFASsbSignal, -1); + err_code += gn_fa_ssb((*c)->obj_key, GnFASsbWO, -1); + + // configure sample-rate, data-rate, shift frequency, and converter offset + err_code += gn_fa_fsample((*c)->obj_key, (*c)->sample_rate); + err_code += gn_fa_fdata((*c)->obj_key, (*c)->sample_rate); + err_code += gn_fa_fshift((*c)->obj_key, 0.0); + err_code += gn_fa_conv_offset((*c)->obj_key, false); + + return (err_code); +} + +int gn_config_fa(gn::real_t fixed_tone_freq, gn_config *c) { + int err_code; + + if (!(*c)) { + gn_config c_p; + c_p = (gn_config)calloc(1, sizeof(*c_p)); + if (!(c_p)) { + printf("insufficient memory\n"); + return ENOMEM; + } else + *c = c_p; + } + + if ((*c)->sample_rate <= 0) { + printf("ERROR: Sample rate must be set before configuring Fourier analysis\n"); + return gn_failure; + } + + (*c)->obj_key = (char *)calloc(3, sizeof(char)); + strcpy((*c)->obj_key, "fa"); + (*c)->comp_key = (char *)calloc(2, sizeof(char)); + strcpy((*c)->comp_key, "A"); + + (*c)->ssb_fund = 120; + (*c)->ssb_rest = 0; + (*c)->max_harm_order = 3; + (*c)->axis_type = GnFreqAxisTypeDcCenter; + + // configure object key for Fourier analysis + err_code = gn_fa_create((*c)->obj_key); + + // configure component key for Fourier analysis + err_code += gn_fa_fixed_tone((*c)->obj_key, (*c)->comp_key, + GnFACompTagSignal, fixed_tone_freq, + (*c)->ssb_fund); + + // configure harmonic order for Fourier analysis + err_code += gn_fa_hd((*c)->obj_key, (*c)->max_harm_order); + + // configure single-side bins for Fourier analysis + err_code += gn_fa_ssb((*c)->obj_key, GnFASsbDefault, (*c)->ssb_rest); + err_code += gn_fa_ssb((*c)->obj_key, GnFASsbDC, -1); + err_code += gn_fa_ssb((*c)->obj_key, GnFASsbSignal, -1); + err_code += gn_fa_ssb((*c)->obj_key, GnFASsbWO, -1); + + // configure sample-rate, data-rate, shift frequency, and converter offset + err_code += gn_fa_fsample((*c)->obj_key, (*c)->sample_rate); + err_code += gn_fa_fdata((*c)->obj_key, (*c)->sample_rate); + err_code += gn_fa_fshift((*c)->obj_key, 0.0); + err_code += gn_fa_conv_offset((*c)->obj_key, false); + + return (err_code); +} + +// waveform generation +int gn_gen_ramp(gn::real_t **out, gn_config *c) { + int err_code; + gn::real_t *awf = (gn::real_t *)calloc((*c)->npts, sizeof(gn::real_t)); + err_code = gn_ramp(awf, (*c)->npts, (*c)->ramp_start, (*c)->ramp_stop, + (*c)->noise_rms); + *out = awf; + + return err_code; +} + +int gn_gen_real_tone(gn::real_t **out, gn_config *c) { + int err_code = 0; + gn::real_t *awf = (gn::real_t *)calloc((*c)->npts, sizeof(gn::real_t)); + + for (size_t i = 0; i < (*c)->num_tones; i++) { + gn::real_t *tmp = + (gn::real_t *)calloc((*c)->npts, sizeof(gn::real_t)); + if ((*c)->ttype == REAL_COSINE) + err_code = gn_cos(tmp, (*c)->npts, (*c)->sample_rate, + (*c)->tone_ampl[i], + (*c)->tone_freq[i], + (*c)->tone_phase[i], 0, 0); + else if ((*c)->ttype == REAL_SINE) + err_code = gn_sin(tmp, (*c)->npts, (*c)->sample_rate, + (*c)->tone_ampl[i], + (*c)->tone_freq[i], + (*c)->tone_phase[i], 0, 0); + if (!err_code) { + for (size_t j = 0; j < (*c)->npts; j++) + awf[j] = awf[j] + tmp[j]; + } + } + *out = awf; + + return err_code; +} + +int gn_gen_complex_tone(gn::real_t **outi, gn::real_t **outq, gn_config *c) { + int err_code = 0; + gn::real_t *awfi = (gn::real_t *)calloc((*c)->npts, sizeof(gn::real_t)); + gn::real_t *awfq = (gn::real_t *)calloc((*c)->npts, sizeof(gn::real_t)); + + for (size_t i = 0; i < (*c)->num_tones; i++) { + gn::real_t *tmp = + (gn::real_t *)calloc((*c)->npts, sizeof(gn::real_t)); + err_code = gn_cos(tmp, (*c)->npts, (*c)->sample_rate, + (*c)->tone_ampl[i], (*c)->tone_freq[i], + (*c)->tone_phase[i], 0, 0); + if (!err_code) { + for (size_t j = 0; j < (*c)->npts; j++) + awfi[j] = awfi[j] + tmp[j]; + } + tmp = (gn::real_t *)calloc((*c)->npts, sizeof(gn::real_t)); + err_code = gn_sin(tmp, (*c)->npts, (*c)->sample_rate, + (*c)->tone_ampl[i], (*c)->tone_freq[i], + (*c)->tone_phase[i], 0, 0); + if (!err_code) { + for (size_t j = 0; j < (*c)->npts; j++) + awfq[j] = awfq[j] + tmp[j]; + } + } + *outi = awfi; + *outq = awfq; + + return err_code; +} + +// processing +int gn_quantize(int32_t **out, const gn::real_t *in, gn_config *c) { + int err_code; + int32_t *qwf = (int32_t *)calloc((*c)->npts, sizeof(int32_t)); + + err_code = gn_quantize32(qwf, (*c)->npts, in, (*c)->npts, (*c)->fsr, + (*c)->qres, (*c)->noise_rms, + (*c)->code_format); + *out = qwf; + + return err_code; +} + +int gn_fftz(gn::real_t **out, const int32_t *in_i, const int32_t *in_q, + gn_config *c) { + int err_code; + gn::real_t *fft_of_in = + (gn::real_t *)calloc(2 * (*c)->nfft, sizeof(gn::real_t)); + + err_code = gn_fft32(fft_of_in, 2 * (*c)->nfft, in_i, (*c)->npts, in_q, + (*c)->npts, (*c)->qres, (*c)->fft_navg, (*c)->nfft, + (*c)->win, (*c)->code_format); + *out = fft_of_in; + + return err_code; +} + +int gn_histz(uint64_t **hist, size_t *hist_len, const int32_t *qwf, + gn_config *c) { + int err_code; + uint64_t *out = NULL; + + err_code = gn_code_density_size(&((*c)->_code_density_size), (*c)->qres, + (*c)->code_format); + out = (uint64_t *)calloc((*c)->_code_density_size, sizeof(uint64_t)); + err_code += gn_hist32(out, (*c)->_code_density_size, qwf, (*c)->npts, + (*c)->qres, (*c)->code_format, false); + *hist = out; + *hist_len = (*c)->_code_density_size; + + return err_code; +} + +int gn_dnlz(double **dnl, size_t *dnl_len, const uint64_t *hist, gn_config *c) { + int err_code; + double *out = NULL; + + err_code = gn_code_density_size(&((*c)->_code_density_size), (*c)->qres, + (*c)->code_format); + out = (double *)calloc((*c)->_code_density_size, sizeof(double)); + err_code = gn_dnl(out, (*c)->_code_density_size, hist, + (*c)->_code_density_size, (*c)->dnla_signal_type); + *dnl = out; + *dnl_len = (*c)->_code_density_size; + + return err_code; +} + +int gn_inlz(double **inl, size_t *inl_len, const double *dnl, gn_config *c) { + int err_code; + double *out = NULL; + + err_code = gn_code_density_size(&((*c)->_code_density_size), (*c)->qres, + (*c)->code_format); + out = (double *)calloc((*c)->_code_density_size, sizeof(double)); + err_code = gn_inl(out, (*c)->_code_density_size, dnl, + (*c)->_code_density_size, (*c)->inla_fit); + *inl = out; + *inl_len = (*c)->_code_density_size; + + return err_code; +} + +// Waveform/Histogram/DNL/INL/Fourier Analysis +int gn_get_wfa_results(char ***rkeys, gn::real_t **rvalues, + size_t *results_size, const int32_t *qwf, gn_config *c) { + int err_code = 0; + + // get results size + err_code = gn_analysis_results_size(&((*c)->_wfa_results_size), + GnAnalysisTypeWaveform); + + // allocate memory for result keys and values + (*c)->_wfa_result_keys = + (char **)calloc(((*c)->_wfa_results_size), sizeof(char *)); + (*c)->_wfa_result_values = (gn::real_t *)calloc( + ((*c)->_wfa_results_size), sizeof(gn::real_t)); + + // get result key sizes + (*c)->_wfa_result_key_sizes = + (size_t *)calloc(((*c)->_wfa_results_size), sizeof(size_t)); + err_code += gn_analysis_results_key_sizes((*c)->_wfa_result_key_sizes, + (*c)->_wfa_results_size, + GnAnalysisTypeWaveform); + + // allocate memory for each result key + for (size_t i = 0; i < (*c)->_wfa_results_size; ++i) + (*c)->_wfa_result_keys[i] = (char *)calloc( + (*c)->_wfa_result_key_sizes[i], sizeof(char)); + + // execute analysis + err_code += gn_wf_analysis32((*c)->_wfa_result_keys, + (*c)->_wfa_results_size, + (*c)->_wfa_result_values, + (*c)->_wfa_results_size, qwf, (*c)->npts); + + // copy keys + *rkeys = (char **)calloc(((*c)->_wfa_results_size), sizeof(char *)); + for (size_t i = 0; i < (*c)->_wfa_results_size; ++i) + (*rkeys)[i] = (char *)calloc((*c)->_wfa_result_key_sizes[i], + sizeof(char)); + + // copy values + *rvalues = (gn::real_t *)calloc(((*c)->_wfa_results_size), + sizeof(gn::real_t)); + for (size_t i = 0; i < (*c)->_wfa_results_size; ++i) { + strcpy((*rkeys)[i], (*c)->_wfa_result_keys[i]); + (*rvalues)[i] = (*c)->_wfa_result_values[i]; + } + *results_size = (*c)->_wfa_results_size; + + return (err_code); +} + +int gn_get_ha_results(char ***rkeys, gn::real_t **rvalues, size_t *results_size, + const uint64_t *hist, gn_config *c) { + int err_code = 0; + + // get results size + err_code = gn_analysis_results_size(&((*c)->_hist_results_size), + GnAnalysisTypeHistogram); + + // allocate memory for result keys and values + (*c)->_hist_result_keys = + (char **)calloc(((*c)->_hist_results_size), sizeof(char *)); + (*c)->_hist_result_values = (gn::real_t *)calloc( + ((*c)->_hist_results_size), sizeof(gn::real_t)); + + // get result key sizes + (*c)->_hist_result_key_sizes = + (size_t *)calloc(((*c)->_hist_results_size), sizeof(size_t)); + err_code += gn_analysis_results_key_sizes((*c)->_hist_result_key_sizes, + (*c)->_hist_results_size, + GnAnalysisTypeHistogram); + + // allocate memory for each result key + for (size_t i = 0; i < (*c)->_hist_results_size; ++i) + (*c)->_hist_result_keys[i] = (char *)calloc( + (*c)->_hist_result_key_sizes[i], sizeof(char)); + + // execute analysis + err_code += gn_hist_analysis((*c)->_hist_result_keys, + (*c)->_hist_results_size, + (*c)->_hist_result_values, + (*c)->_hist_results_size, hist, + (*c)->_code_density_size); + + // copy keys + *rkeys = (char **)calloc(((*c)->_hist_results_size), sizeof(char *)); + for (size_t i = 0; i < (*c)->_hist_results_size; ++i) + (*rkeys)[i] = (char *)calloc((*c)->_hist_result_key_sizes[i], + sizeof(char)); + + // copy values + *rvalues = (gn::real_t *)calloc(((*c)->_hist_results_size), + sizeof(gn::real_t)); + for (size_t i = 0; i < (*c)->_hist_results_size; ++i) { + strcpy((*rkeys)[i], (*c)->_hist_result_keys[i]); + (*rvalues)[i] = (*c)->_hist_result_values[i]; + } + *results_size = (*c)->_hist_results_size; + + return (err_code); +} + +int gn_get_dnla_results(char ***rkeys, gn::real_t **rvalues, + size_t *results_size, const gn::real_t *dnl, + gn_config *c) { + int err_code; + + // get results size + err_code = gn_analysis_results_size(&((*c)->_dnl_results_size), + GnAnalysisTypeDNL); + + // allocate memory for result keys and values + (*c)->_dnl_result_keys = + (char **)calloc(((*c)->_dnl_results_size), sizeof(char *)); + (*c)->_dnl_result_values = (gn::real_t *)calloc( + ((*c)->_dnl_results_size), sizeof(gn::real_t)); + + // get result key sizes + (*c)->_dnl_result_key_sizes = + (size_t *)calloc(((*c)->_dnl_results_size), sizeof(size_t)); + err_code += gn_analysis_results_key_sizes((*c)->_dnl_result_key_sizes, + (*c)->_dnl_results_size, + GnAnalysisTypeDNL); + + // allocate memory for each result key + for (size_t i = 0; i < (*c)->_dnl_results_size; ++i) + (*c)->_dnl_result_keys[i] = (char *)calloc( + (*c)->_dnl_result_key_sizes[i], sizeof(char)); + + // execute analysis + err_code += gn_dnl_analysis((*c)->_dnl_result_keys, + (*c)->_dnl_results_size, + (*c)->_dnl_result_values, + (*c)->_dnl_results_size, dnl, + (*c)->_code_density_size); + + // copy keys + *rkeys = (char **)calloc(((*c)->_dnl_results_size), sizeof(char *)); + for (size_t i = 0; i < (*c)->_dnl_results_size; ++i) + (*rkeys)[i] = (char *)calloc((*c)->_dnl_result_key_sizes[i], + sizeof(char)); + + // copy values + *rvalues = (gn::real_t *)calloc(((*c)->_dnl_results_size), + sizeof(gn::real_t)); + for (size_t i = 0; i < (*c)->_dnl_results_size; ++i) { + strcpy((*rkeys)[i], (*c)->_dnl_result_keys[i]); + (*rvalues)[i] = (*c)->_dnl_result_values[i]; + } + *results_size = (*c)->_dnl_results_size; + + return (err_code); +} + +int gn_get_inla_results(char ***rkeys, gn::real_t **rvalues, + size_t *results_size, const gn::real_t *inl, + gn_config *c) { + int err_code; + + // get results size + err_code = gn_analysis_results_size(&((*c)->_inl_results_size), + GnAnalysisTypeINL); + + // allocate memory for result keys and values + (*c)->_inl_result_keys = + (char **)calloc(((*c)->_inl_results_size), sizeof(char *)); + (*c)->_inl_result_values = (gn::real_t *)calloc( + ((*c)->_inl_results_size), sizeof(gn::real_t)); + + // get result key sizes + (*c)->_inl_result_key_sizes = + (size_t *)calloc(((*c)->_inl_results_size), sizeof(size_t)); + err_code += gn_analysis_results_key_sizes((*c)->_inl_result_key_sizes, + (*c)->_inl_results_size, + GnAnalysisTypeINL); + + // allocate memory for each result key + for (size_t i = 0; i < (*c)->_inl_results_size; ++i) + (*c)->_inl_result_keys[i] = (char *)calloc( + (*c)->_inl_result_key_sizes[i], sizeof(char)); + + // execute analysis + err_code += gn_inl_analysis((*c)->_inl_result_keys, + (*c)->_inl_results_size, + (*c)->_inl_result_values, + (*c)->_inl_results_size, inl, + (*c)->_code_density_size); + + // copy keys + *rkeys = (char **)calloc(((*c)->_inl_results_size), sizeof(char *)); + for (size_t i = 0; i < (*c)->_inl_results_size; ++i) + (*rkeys)[i] = (char *)calloc((*c)->_inl_result_key_sizes[i], + sizeof(char)); + + // copy values + *rvalues = (gn::real_t *)calloc(((*c)->_inl_results_size), + sizeof(gn::real_t)); + for (size_t i = 0; i < (*c)->_inl_results_size; ++i) { + strcpy((*rkeys)[i], (*c)->_inl_result_keys[i]); + (*rvalues)[i] = (*c)->_inl_result_values[i]; + } + *results_size = (*c)->_inl_results_size; + + return (err_code); +} + +int gn_get_fa_single_result(gn::real_t *rvalue, const char *metric_name, + gn::real_t *fft_ilv, gn_config *c) { + int err_code; + size_t i; + bool metric_found = false; + size_t results_size; + char **rkeys; + double *rvalues; + + // compute all results + err_code = gn_get_fa_results(&rkeys, &rvalues, &results_size, fft_ilv, + &(*c)); + for (i = 0; i < results_size; i++) { + if (!strcmp(metric_name, rkeys[i])) { + metric_found = true; + break; + } + } + if (!metric_found) { + printf("ERROR: Invalid selection of metric\n"); + return gn_failure; + } + *rvalue = rvalues[i]; + + return err_code; +} + +int gn_get_fa_results(char ***rkeys, gn::real_t **rvalues, size_t *results_size, + gn::real_t *fft_ilv, gn_config *c) { + int err_code = 0; + size_t *result_key_sizes; + + // get results size + err_code = gn_fft_analysis_results_size(results_size, (*c)->obj_key, + 2 * (*c)->nfft, (*c)->nfft); + + // allocate memory for result keys and values + *rkeys = (char **)calloc(*results_size, sizeof(char *)); + *rvalues = (gn::real_t *)calloc(*results_size, sizeof(gn::real_t)); + + // get result key sizes + result_key_sizes = (size_t *)calloc(*results_size, sizeof(size_t)); + err_code += gn_fft_analysis_results_key_sizes( + result_key_sizes, *results_size, (*c)->obj_key, 2 * (*c)->nfft, + (*c)->nfft); + + // allocate memory for each result key + for (size_t i = 0; i < *results_size; ++i) + (*rkeys)[i] = (char *)calloc(result_key_sizes[i], sizeof(char)); + + // execute analysis + err_code += gn_fft_analysis(*rkeys, *results_size, *rvalues, + *results_size, (*c)->obj_key, fft_ilv, + 2 * (*c)->nfft, (*c)->nfft, + (*c)->axis_type); + + return (err_code); +} } \ No newline at end of file diff --git a/bindings/python/genalyzer/__init__.py b/bindings/python/genalyzer/__init__.py index 96d18a9..2ffaeda 100644 --- a/bindings/python/genalyzer/__init__.py +++ b/bindings/python/genalyzer/__init__.py @@ -1,6 +1,8 @@ +# Copyright (C) 2024 Analog Devices, Inc. +# +# SPDX short identifier: ADIBSD OR GPL-2.0-or-later """Python bindings for Genalyzer""" -# Version of the genalyzer bindings (which may be different than the library version) __version__ = "0.1.1" __author__ = "Analog Devices, Inc." diff --git a/bindings/python/genalyzer/helpers/__init__.py b/bindings/python/genalyzer/helpers/__init__.py index 0d382a4..2d572aa 100644 --- a/bindings/python/genalyzer/helpers/__init__.py +++ b/bindings/python/genalyzer/helpers/__init__.py @@ -1,3 +1,6 @@ +# Copyright (C) 2024 Analog Devices, Inc. +# +# SPDX short identifier: ADIBSD OR GPL-2.0-or-later try: from .waveform_gen import WaveformGen except ImportError: diff --git a/bindings/python/genalyzer/helpers/waveform_gen.py b/bindings/python/genalyzer/helpers/waveform_gen.py index 883d697..64e94a8 100644 --- a/bindings/python/genalyzer/helpers/waveform_gen.py +++ b/bindings/python/genalyzer/helpers/waveform_gen.py @@ -1,3 +1,6 @@ +# Copyright (C) 2024 Analog Devices, Inc. +# +# SPDX short identifier: ADIBSD OR GPL-2.0-or-later from ..simplified_beta import ( config_gen_tone, gen_real_tone, diff --git a/bindings/python/genalyzer/pygenalyzer.py b/bindings/python/genalyzer/pygenalyzer.py index a199690..10b392f 100644 --- a/bindings/python/genalyzer/pygenalyzer.py +++ b/bindings/python/genalyzer/pygenalyzer.py @@ -1,23 +1,6 @@ -""" -* pygenalyzer - genalyzer API header file -* -* Copyright (C) 2022 Analog Devices, Inc. -* Author: Peter Derounian -* -* 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. -""" +# Copyright (C) 2024 Analog Devices, Inc. +# +# SPDX short identifier: ADIBSD OR GPL-2.0-or-later """ Python wrapper for Genalyzer Library (genalyzer_plus_plus) diff --git a/bindings/python/genalyzer/simplified_beta/__init__.py b/bindings/python/genalyzer/simplified_beta/__init__.py index 89a94fb..e720414 100644 --- a/bindings/python/genalyzer/simplified_beta/__init__.py +++ b/bindings/python/genalyzer/simplified_beta/__init__.py @@ -1,3 +1,6 @@ +# Copyright (C) 2024 Analog Devices, Inc. +# +# SPDX short identifier: ADIBSD OR GPL-2.0-or-later from .simplified_beta import ( config_free, config_gen_ramp, diff --git a/bindings/python/genalyzer/simplified_beta/simplified_beta.py b/bindings/python/genalyzer/simplified_beta/simplified_beta.py index 1e233b3..49b6d50 100644 --- a/bindings/python/genalyzer/simplified_beta/simplified_beta.py +++ b/bindings/python/genalyzer/simplified_beta/simplified_beta.py @@ -1,23 +1,6 @@ -""" -* cgenalyzer - genalyzer API header file -* -* Copyright (C) 2022 Analog Devices, Inc. -* Author: Srikanth Pagadarai -* -* 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. -""" +# Copyright (C) 2024 Analog Devices, Inc. +# +# SPDX short identifier: ADIBSD OR GPL-2.0-or-later from dataclasses import dataclass, field diff --git a/cmake/FindBreathe.cmake b/cmake/FindBREATHE.cmake similarity index 80% rename from cmake/FindBreathe.cmake rename to cmake/FindBREATHE.cmake index 239a224..0aed416 100644 --- a/cmake/FindBreathe.cmake +++ b/cmake/FindBREATHE.cmake @@ -7,7 +7,7 @@ if(BREATHE_APIDOC) endif() include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Breathe REQUIRED_VARS BREATHE_APIDOC +find_package_handle_standard_args(BREATHE REQUIRED_VARS BREATHE_APIDOC VERSION_VAR BREATHE_VERSION ) diff --git a/cmake/FindFFTW.cmake b/cmake/FindFFTW.cmake index fb8476d..af52847 100644 --- a/cmake/FindFFTW.cmake +++ b/cmake/FindFFTW.cmake @@ -230,113 +230,113 @@ else() PATHS ${PKG_FFTW_INCLUDE_DIRS} ${INCLUDE_INSTALL_DIR} ) -endif( FFTW_ROOT ) +endif() #--------------------------------------- components -if (FFTW_DOUBLE_LIB) +if(FFTW_DOUBLE_LIB) set(FFTW_DOUBLE_LIB_FOUND TRUE) set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_DOUBLE_LIB}) add_library(FFTW::Double INTERFACE IMPORTED) set_target_properties(FFTW::Double PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" - INTERFACE_LINK_LIBRARIES "${FFTW_DOUBLE_LIB}" + INTERFACE_LINK_LIBRARIES "${FFTW_DOUBLE_LIB}" ) else() set(FFTW_DOUBLE_LIB_FOUND FALSE) endif() -if (FFTW_FLOAT_LIB) +if(FFTW_FLOAT_LIB) set(FFTW_FLOAT_LIB_FOUND TRUE) set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_FLOAT_LIB}) add_library(FFTW::Float INTERFACE IMPORTED) set_target_properties(FFTW::Float PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" - INTERFACE_LINK_LIBRARIES "${FFTW_FLOAT_LIB}" + INTERFACE_LINK_LIBRARIES "${FFTW_FLOAT_LIB}" ) else() set(FFTW_FLOAT_LIB_FOUND FALSE) endif() -if (FFTW_LONGDOUBLE_LIB) +if(FFTW_LONGDOUBLE_LIB) set(FFTW_LONGDOUBLE_LIB_FOUND TRUE) set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_LONGDOUBLE_LIB}) add_library(FFTW::LongDouble INTERFACE IMPORTED) set_target_properties(FFTW::LongDouble PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" - INTERFACE_LINK_LIBRARIES "${FFTW_LONGDOUBLE_LIB}" + INTERFACE_LINK_LIBRARIES "${FFTW_LONGDOUBLE_LIB}" ) else() set(FFTW_LONGDOUBLE_LIB_FOUND FALSE) endif() -if (FFTW_DOUBLE_THREADS_LIB) +if(FFTW_DOUBLE_THREADS_LIB) set(FFTW_DOUBLE_THREADS_LIB_FOUND TRUE) set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_DOUBLE_THREADS_LIB}) add_library(FFTW::DoubleThreads INTERFACE IMPORTED) set_target_properties(FFTW::DoubleThreads PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" - INTERFACE_LINK_LIBRARIES "${FFTW_DOUBLETHREADS_LIB}" + INTERFACE_LINK_LIBRARIES "${FFTW_DOUBLETHREADS_LIB}" ) else() set(FFTW_DOUBLE_THREADS_LIB_FOUND FALSE) endif() -if (FFTW_FLOAT_THREADS_LIB) +if(FFTW_FLOAT_THREADS_LIB) set(FFTW_FLOAT_THREADS_LIB_FOUND TRUE) set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_FLOAT_THREADS_LIB}) add_library(FFTW::FloatThreads INTERFACE IMPORTED) set_target_properties(FFTW::FloatThreads PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" - INTERFACE_LINK_LIBRARIES "${FFTW_FLOAT_THREADS_LIB}" + INTERFACE_LINK_LIBRARIES "${FFTW_FLOAT_THREADS_LIB}" ) else() set(FFTW_FLOAT_THREADS_LIB_FOUND FALSE) endif() -if (FFTW_LONGDOUBLE_THREADS_LIB) +if(FFTW_LONGDOUBLE_THREADS_LIB) set(FFTW_LONGDOUBLE_THREADS_LIB_FOUND TRUE) set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_LONGDOUBLE_THREADS_LIB}) add_library(FFTW::LongDoubleThreads INTERFACE IMPORTED) set_target_properties(FFTW::LongDoubleThreads PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" - INTERFACE_LINK_LIBRARIES "${FFTW_LONGDOUBLE_THREADS_LIB}" + INTERFACE_LINK_LIBRARIES "${FFTW_LONGDOUBLE_THREADS_LIB}" ) else() set(FFTW_LONGDOUBLE_THREADS_LIB_FOUND FALSE) endif() -if (FFTW_DOUBLE_OPENMP_LIB) +if(FFTW_DOUBLE_OPENMP_LIB) set(FFTW_DOUBLE_OPENMP_LIB_FOUND TRUE) set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_DOUBLE_OPENMP_LIB}) add_library(FFTW::DoubleOpenMP INTERFACE IMPORTED) set_target_properties(FFTW::DoubleOpenMP PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" - INTERFACE_LINK_LIBRARIES "${FFTW_DOUBLE_OPENMP_LIB}" + INTERFACE_LINK_LIBRARIES "${FFTW_DOUBLE_OPENMP_LIB}" ) else() set(FFTW_DOUBLE_OPENMP_LIB_FOUND FALSE) endif() -if (FFTW_FLOAT_OPENMP_LIB) +if(FFTW_FLOAT_OPENMP_LIB) set(FFTW_FLOAT_OPENMP_LIB_FOUND TRUE) set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_FLOAT_OPENMP_LIB}) add_library(FFTW::FloatOpenMP INTERFACE IMPORTED) set_target_properties(FFTW::FloatOpenMP PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" - INTERFACE_LINK_LIBRARIES "${FFTW_FLOAT_OPENMP_LIB}" + INTERFACE_LINK_LIBRARIES "${FFTW_FLOAT_OPENMP_LIB}" ) else() set(FFTW_FLOAT_OPENMP_LIB_FOUND FALSE) endif() -if (FFTW_LONGDOUBLE_OPENMP_LIB) +if(FFTW_LONGDOUBLE_OPENMP_LIB) set(FFTW_LONGDOUBLE_OPENMP_LIB_FOUND TRUE) set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_LONGDOUBLE_OPENMP_LIB}) add_library(FFTW::LongDoubleOpenMP INTERFACE IMPORTED) set_target_properties(FFTW::LongDoubleOpenMP PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" - INTERFACE_LINK_LIBRARIES "${FFTW_LONGDOUBLE_OPENMP_LIB}" + INTERFACE_LINK_LIBRARIES "${FFTW_LONGDOUBLE_OPENMP_LIB}" ) else() set(FFTW_LONGDOUBLE_OPENMP_LIB_FOUND FALSE) diff --git a/cmake/FindSPHINX.cmake b/cmake/FindSPHINX.cmake new file mode 100644 index 0000000..1d37510 --- /dev/null +++ b/cmake/FindSPHINX.cmake @@ -0,0 +1,7 @@ +#Look for an executable called sphinx-build +find_program(SPHINX_EXECUTABLE NAMES sphinx-build DOC "Path to sphinx-build executable") + +include(FindPackageHandleStandardArgs) + +#Handle standard arguments to find_package like REQUIRED and QUIET +find_package_handle_standard_args(SPHINX "Failed to find sphinx-build executable" SPHINX_EXECUTABLE) diff --git a/cmake/FindSphinx.cmake b/cmake/FindSphinx.cmake deleted file mode 100644 index 990f979..0000000 --- a/cmake/FindSphinx.cmake +++ /dev/null @@ -1,11 +0,0 @@ -#Look for an executable called sphinx-build -find_program(SPHINX_EXECUTABLE - NAMES sphinx-build - DOC "Path to sphinx-build executable") - -include(FindPackageHandleStandardArgs) - -#Handle standard arguments to find_package like REQUIRED and QUIET -find_package_handle_standard_args(Sphinx - "Failed to find sphinx-build executable" - SPHINX_EXECUTABLE) diff --git a/cmake/Modules/Findgenalyzer_plus_plus.cmake b/cmake/Modules/FindGENALYZER_PLUS_PLUS.cmake similarity index 80% rename from cmake/Modules/Findgenalyzer_plus_plus.cmake rename to cmake/Modules/FindGENALYZER_PLUS_PLUS.cmake index 9b60c2f..9d14a58 100644 --- a/cmake/Modules/Findgenalyzer_plus_plus.cmake +++ b/cmake/Modules/FindGENALYZER_PLUS_PLUS.cmake @@ -1,5 +1,5 @@ if(NOT GENALYZER_PLUS_PLUS_FOUND) - find_path(GENALYZER_PLUS_PLUS_INCLUDE_DIRS + find_path(GENALYZER_PLUS_PLUS_INCLUDE_DIRS NAMES array_ops.hpp code_density.hpp @@ -30,8 +30,8 @@ if(NOT GENALYZER_PLUS_PLUS_FOUND) /usr/local/include/ ) - find_library(GENALYZER_PLUS_PLUS_LIBRARIES - NAMES + find_library(GENALYZER_PLUS_PLUS_LIBRARIES + NAMES genalyzer_plus_plus PATHS /usr/lib @@ -41,11 +41,11 @@ if(NOT GENALYZER_PLUS_PLUS_FOUND) if(GENALYZER_PLUS_PLUS_INCLUDE_DIRS AND GENALYZER_PLUS_PLUS_LIBRARIES) set(GENALYZER_PLUS_PLUS_FOUND TRUE CACHE INTERNAL "libgenalyzer_plus_plus found") message(STATUS "Found libgenalyzer_plus_plus: ${GENALYZER_PLUS_PLUS_INCLUDE_DIRS}, ${GENALYZER_PLUS_PLUS_LIBRARIES}") -else(GENALYZER_PLUS_PLUS_INCLUDE_DIRS AND GENALYZER_PLUS_PLUS_LIBRARIES) +else() set(GENALYZER_PLUS_PLUS_FOUND FALSE CACHE INTERNAL "libgenalyzer_plus_plus found") message(STATUS "libgenalyzer_plus_plus not found.") -endif(GENALYZER_PLUS_PLUS_INCLUDE_DIRS AND GENALYZER_PLUS_PLUS_LIBRARIES) +endif() mark_as_advanced(GENALYZER_PLUS_PLUS_LIBRARIES AND GENALYZER_PLUS_PLUS_INCLUDE_DIRS) -endif(NOT GENALYZER_PLUS_PLUS_FOUND) +endif() diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 1676d3a..4c74c31 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -10,14 +10,14 @@ configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY) file(MAKE_DIRECTORY ${DOXYGEN_OUTPUT_DIR}) add_custom_command(OUTPUT ${DOXYGEN_INDEX_FILE} - DEPENDS ${GENALYZER_PUBLIC_HEADERS} - COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT} - MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN} - COMMENT "Generating docs") + DEPENDS ${GENALYZER_PUBLIC_HEADERS} + COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT} + MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN} + COMMENT "Generating docs") add_custom_target(Doxygen ALL DEPENDS ${DOXYGEN_INDEX_FILE}) -find_package(Sphinx REQUIRED) +find_package(SPHINX REQUIRED) set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}) set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/sphinx) diff --git a/include/array_ops.hpp b/include/array_ops.hpp index 5f24aa5..761de33 100644 --- a/include/array_ops.hpp +++ b/include/array_ops.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_ARRAY_OPS_HPP #define GENALYZER_IMPL_ARRAY_OPS_HPP @@ -5,17 +8,23 @@ namespace genalyzer_impl { - void abs(const real_t* in_data, size_t in_size, real_t* out_data, size_t out_size); +void abs(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size); - void angle(const real_t* in_data, size_t in_size, real_t* out_data, size_t out_size); +void angle(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size); - void db(const real_t* in_data, size_t in_size, real_t* out_data, size_t out_size); +void db(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size); - void db10(const real_t* in_data, size_t in_size, real_t* out_data, size_t out_size); +void db10(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size); - void db20(const real_t* in_data, size_t in_size, real_t* out_data, size_t out_size); +void db20(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size); - void norm(const real_t* in_data, size_t in_size, real_t* out_data, size_t out_size); +void norm(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size); } // namespace genalyzer_impl diff --git a/include/code_density.hpp b/include/code_density.hpp index 9cb1fa2..c0e17cb 100644 --- a/include/code_density.hpp +++ b/include/code_density.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_CODE_DENSITY_HPP #define GENALYZER_IMPL_CODE_DENSITY_HPP @@ -8,63 +11,39 @@ namespace genalyzer_impl { - size_t code_density_size(int n, CodeFormat format); - - size_t code_densityx_size(int64_t min, int64_t max); - - void code_axis(real_t* data, size_t size, int n, CodeFormat format); - - void code_axisx(real_t* data, size_t size, int64_t min, int64_t max); - - void dnl( - real_t* dnl_data, - size_t dnl_size, - const uint64_t* hist_data, - size_t hist_size, - DnlSignal type - ); - - std::map dnl_analysis(const real_t* data, size_t size); - - const std::vector& dnl_analysis_ordered_keys(); - - template - void hist( - uint64_t* hist_data, - size_t hist_size, - const T* wf_data, - size_t wf_size, - int n, - CodeFormat format, - bool preserve - ); - - template - void histx( - uint64_t* hist_data, - size_t hist_size, - const T* wf_data, - size_t wf_size, - int64_t min, - int64_t max, - bool preserve - ); - - std::map hist_analysis(const uint64_t* data, size_t size); - - const std::vector& hist_analysis_ordered_keys(); - - void inl( - real_t* inl_data, - size_t inl_size, - const real_t* dnl_data, - size_t dnl_size, - InlLineFit fit - ); - - std::map inl_analysis(const real_t* data, size_t size); - - const std::vector& inl_analysis_ordered_keys(); +size_t code_density_size(int n, CodeFormat format); + +size_t code_densityx_size(int64_t min, int64_t max); + +void code_axis(real_t *data, size_t size, int n, CodeFormat format); + +void code_axisx(real_t *data, size_t size, int64_t min, int64_t max); + +void dnl(real_t *dnl_data, size_t dnl_size, const uint64_t *hist_data, + size_t hist_size, DnlSignal type); + +std::map dnl_analysis(const real_t *data, size_t size); + +const std::vector &dnl_analysis_ordered_keys(); + +template +void hist(uint64_t *hist_data, size_t hist_size, const T *wf_data, + size_t wf_size, int n, CodeFormat format, bool preserve); + +template +void histx(uint64_t *hist_data, size_t hist_size, const T *wf_data, + size_t wf_size, int64_t min, int64_t max, bool preserve); + +std::map hist_analysis(const uint64_t *data, size_t size); + +const std::vector &hist_analysis_ordered_keys(); + +void inl(real_t *inl_data, size_t inl_size, const real_t *dnl_data, + size_t dnl_size, InlLineFit fit); + +std::map inl_analysis(const real_t *data, size_t size); + +const std::vector &inl_analysis_ordered_keys(); } // namespace genalyzer_impl diff --git a/include/constants.hpp b/include/constants.hpp index 500f65d..0989819 100644 --- a/include/constants.hpp +++ b/include/constants.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_CONSTANTS_HPP #define GENALYZER_IMPL_CONSTANTS_HPP @@ -7,27 +10,27 @@ namespace genalyzer_impl { - const real_t k_half = 0.5; - const real_t k_one = 1.0; - const real_t k_two = 2.0; - const real_t k_sqrt2 = std::sqrt(k_two); - const real_t k_inv_sqrt2 = std::sqrt(k_half); - const real_t k_pi4 = std::atan(k_one); - const real_t k_pi2 = k_two * k_pi4; - const real_t k_pi = k_two * k_pi2; - const real_t k_2pi = k_two * k_pi; - - const int k_abs_min_code_width = 1; - const int k_abs_max_code_width = 30; - - const size_t k_abs_max_fft_navg = 256; - - const real_t k_abs_max_db = 400.0; - const real_t k_abs_min_db = -400.0; - const real_t k_abs_max_rms = std::pow(10.0, k_abs_max_db / 20.0); - const real_t k_abs_min_rms = std::pow(10.0, k_abs_min_db / 20.0); - const real_t k_abs_max_msq = k_abs_max_rms * k_abs_max_rms; - const real_t k_abs_min_msq = k_abs_min_rms * k_abs_min_rms; +const real_t k_half = 0.5; +const real_t k_one = 1.0; +const real_t k_two = 2.0; +const real_t k_sqrt2 = std::sqrt(k_two); +const real_t k_inv_sqrt2 = std::sqrt(k_half); +const real_t k_pi4 = std::atan(k_one); +const real_t k_pi2 = k_two * k_pi4; +const real_t k_pi = k_two * k_pi2; +const real_t k_2pi = k_two * k_pi; + +const int k_abs_min_code_width = 1; +const int k_abs_max_code_width = 30; + +const size_t k_abs_max_fft_navg = 256; + +const real_t k_abs_max_db = 400.0; +const real_t k_abs_min_db = -400.0; +const real_t k_abs_max_rms = std::pow(10.0, k_abs_max_db / 20.0); +const real_t k_abs_min_rms = std::pow(10.0, k_abs_min_db / 20.0); +const real_t k_abs_max_msq = k_abs_max_rms * k_abs_max_rms; +const real_t k_abs_min_msq = k_abs_min_rms * k_abs_min_rms; } // namespace genalyzer_impl diff --git a/include/enum_map.hpp b/include/enum_map.hpp index b71861b..568a7f8 100644 --- a/include/enum_map.hpp +++ b/include/enum_map.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_ENUM_MAP_HPP #define GENALYZER_IMPL_ENUM_MAP_HPP @@ -9,73 +12,59 @@ namespace genalyzer_impl { - class enum_map - { - public: +class enum_map { +public: + using itos_map_t = std::map; + using stoi_map_t = std::map; + using const_iterator = itos_map_t::const_iterator; - using itos_map_t = std::map; - using stoi_map_t = std::map; - using const_iterator = itos_map_t::const_iterator; +public: + enum_map(const char *name, + std::initializer_list> list); - public: +public: + ~enum_map() = default; - enum_map(const char* name, std::initializer_list> list); +public: // Element Access + const str_t &at(int i) const { + contains(i, true); + return m_itos.at(i); + } - public: + int at(const str_t &s) const { + contains(s, true); + return m_stoi.at(s); + } - ~enum_map() = default; +public: // Iterators + const_iterator begin() const { + return m_itos.begin(); + } - public: // Element Access + const_iterator end() const { + return m_itos.end(); + } - const str_t& at(int i) const - { - contains(i, true); - return m_itos.at(i); - } +public: // Lookup + bool contains(int i, bool throw_if_not_found = false) const; - int at(const str_t& s) const - { - contains(s, true); - return m_stoi.at(s); - } + bool contains(const str_t &s, bool throw_if_not_found = false) const; - public: // Iterators +public: // Other Member Functions + const str_t &name() const { + return m_name; + } - const_iterator begin() const - { - return m_itos.begin(); - } + size_t size() const { + return m_itos.size(); + } - const_iterator end() const - { - return m_itos.end(); - } +private: + str_t m_name; + itos_map_t m_itos; // int to string + stoi_map_t m_stoi; // string to int - public: // Lookup - - bool contains(int i, bool throw_if_not_found = false) const; - - bool contains(const str_t& s, bool throw_if_not_found = false) const; - - public: // Other Member Functions - - const str_t& name() const - { - return m_name; - } - - size_t size() const - { - return m_itos.size(); - } - - private: - - str_t m_name; - itos_map_t m_itos; // int to string - stoi_map_t m_stoi; // string to int - - }; // class enum_map +}; // class enum_map } // namespace genalyzer_impl diff --git a/include/enum_maps.hpp b/include/enum_maps.hpp index 889bfbd..5ed9487 100644 --- a/include/enum_maps.hpp +++ b/include/enum_maps.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_ENUM_MAPS_HPP #define GENALYZER_IMPL_ENUM_MAPS_HPP @@ -7,158 +10,145 @@ namespace genalyzer_impl { - int enum_value(const str_t& enumeration, const str_t& enumerator); - - template - E get_enum(int); - - const enum_map analysis_type_map ("AnalysisType", { - { to_int(AnalysisType::DNL) , "DNL" }, - { to_int(AnalysisType::Fourier) , "Fourier" }, - { to_int(AnalysisType::Histogram) , "Histogram" }, - { to_int(AnalysisType::INL) , "INL" }, - { to_int(AnalysisType::Waveform) , "Waveform" }} - ); - - const enum_map code_format_map ("CodeFormat", { - { to_int(CodeFormat::OffsetBinary) , "OffsetBinary" }, - { to_int(CodeFormat::TwosComplement) , "TwosComplement" }} - ); - - const enum_map dnl_signal_map ("DnlSignal", { - { to_int(DnlSignal::Ramp) , "Ramp" }, - { to_int(DnlSignal::Tone) , "Tone" }} - ); - - const enum_map fa_comp_tag_map ("FACompTag", { - { to_int(FACompTag::DC) , "DC" }, - { to_int(FACompTag::Signal) , "Signal" }, - { to_int(FACompTag::HD) , "HD" }, - { to_int(FACompTag::IMD) , "IMD" }, - { to_int(FACompTag::ILOS) , "ILOS" }, - { to_int(FACompTag::ILGT) , "ILGT" }, - { to_int(FACompTag::CLK) , "CLK" }, - { to_int(FACompTag::UserDist) , "UserDist" }, - { to_int(FACompTag::Noise) , "Noise" }} - ); - - const enum_map fa_ssb_map ("FASsb", { - { to_int(FASsb::Default) , "Default" }, - { to_int(FASsb::DC) , "DC" }, - { to_int(FASsb::Signal) , "Signal" }, - { to_int(FASsb::WO) , "WO" }} - ); - - const enum_map freq_axis_format_map ("FreqAxisFormat", { - { to_int(FreqAxisFormat::Bins) , "Bins" }, - { to_int(FreqAxisFormat::Freq) , "Freq" }, - { to_int(FreqAxisFormat::Norm) , "Norm" }} - ); - - const enum_map freq_axis_type_map ("FreqAxisType", { - { to_int(FreqAxisType::DcCenter) , "DcCenter" }, - { to_int(FreqAxisType::DcLeft) , "DcLeft" }, - { to_int(FreqAxisType::Real) , "Real" }} - ); - - const enum_map inl_line_fit_map ("InlLineFit", { - { to_int(InlLineFit::NoFit) , "NoFit" }, - { to_int(InlLineFit::BestFit) , "BestFit" }, - { to_int(InlLineFit::EndFit) , "EndFit" }} - ); - - const enum_map rfft_scale_map ("RfftScale", { - { to_int(RfftScale::DbfsDc) , "DbfsDc" }, - { to_int(RfftScale::DbfsSin) , "DbfsSin" }, - { to_int(RfftScale::Native) , "Native" }} - ); - - const enum_map window_map ("Window", { - { to_int(Window::NoWindow) , "NoWindow" }, - { to_int(Window::BlackmanHarris) , "BlackmanHarris" }, - { to_int(Window::Hann) , "Hann" }} - ); - +int enum_value(const str_t &enumeration, const str_t &enumerator); + +template +E get_enum(int); + +const enum_map + analysis_type_map("AnalysisType", + { { to_int(AnalysisType::DNL), "DNL" }, + { to_int(AnalysisType::Fourier), "Fourier" }, + { to_int(AnalysisType::Histogram), "Histogram" }, + { to_int(AnalysisType::INL), "INL" }, + { to_int(AnalysisType::Waveform), "Waveform" } }); + +const enum_map code_format_map( + "CodeFormat", + { { to_int(CodeFormat::OffsetBinary), "OffsetBinary" }, + { to_int(CodeFormat::TwosComplement), "TwosComplement" } }); + +const enum_map dnl_signal_map("DnlSignal", + { { to_int(DnlSignal::Ramp), "Ramp" }, + { to_int(DnlSignal::Tone), "Tone" } }); + +const enum_map fa_comp_tag_map("FACompTag", + { { to_int(FACompTag::DC), "DC" }, + { to_int(FACompTag::Signal), "Signal" }, + { to_int(FACompTag::HD), "HD" }, + { to_int(FACompTag::IMD), "IMD" }, + { to_int(FACompTag::ILOS), "ILOS" }, + { to_int(FACompTag::ILGT), "ILGT" }, + { to_int(FACompTag::CLK), "CLK" }, + { to_int(FACompTag::UserDist), "UserDist" }, + { to_int(FACompTag::Noise), "Noise" } }); + +const enum_map fa_ssb_map("FASsb", { { to_int(FASsb::Default), "Default" }, { to_int(FASsb::DC), "DC" }, { to_int(FASsb::Signal), "Signal" }, { to_int(FASsb::WO), "WO" } }); + +const enum_map + freq_axis_format_map("FreqAxisFormat", + { { to_int(FreqAxisFormat::Bins), "Bins" }, + { to_int(FreqAxisFormat::Freq), "Freq" }, + { to_int(FreqAxisFormat::Norm), "Norm" } }); + +const enum_map + freq_axis_type_map("FreqAxisType", + { { to_int(FreqAxisType::DcCenter), "DcCenter" }, + { to_int(FreqAxisType::DcLeft), "DcLeft" }, + { to_int(FreqAxisType::Real), "Real" } }); + +const enum_map inl_line_fit_map("InlLineFit", + { { to_int(InlLineFit::NoFit), "NoFit" }, + { to_int(InlLineFit::BestFit), "BestFit" }, + { to_int(InlLineFit::EndFit), "EndFit" } }); + +const enum_map rfft_scale_map("RfftScale", + { { to_int(RfftScale::DbfsDc), "DbfsDc" }, + { to_int(RfftScale::DbfsSin), "DbfsSin" }, + { to_int(RfftScale::Native), "Native" } }); + +const enum_map window_map("Window", { { to_int(Window::NoWindow), "NoWindow" }, { to_int(Window::BlackmanHarris), "BlackmanHarris" }, { to_int(Window::Hann), "Hann" } }); + } // namespace genalyzer_impl namespace genalyzer_impl { - const enum_map fa_comp_type_map ("FACompType", { - { to_int(FACompType::DC) , "DC" }, - { to_int(FACompType::FixedTone) , "FixedTone" }, - { to_int(FACompType::MaxTone) , "MaxTone" }, - { to_int(FACompType::WOTone) , "WOTone" }} - ); - - const enum_map fa_result_map ("FAResult", { - { to_int(FAResult::AnalysisType) , "analysistype" }, - { to_int(FAResult::SignalType) , "signaltype" }, - { to_int(FAResult::NFFT) , "nfft" }, - { to_int(FAResult::DataSize) , "datasize" }, - { to_int(FAResult::FBin) , "fbin" }, - { to_int(FAResult::FData) , "fdata" }, - { to_int(FAResult::FSample) , "fsample" }, - { to_int(FAResult::FShift) , "fshift" }, - { to_int(FAResult::FSNR) , "fsnr" }, - { to_int(FAResult::SNR) , "snr" }, - { to_int(FAResult::SINAD) , "sinad" }, - { to_int(FAResult::SFDR) , "sfdr" }, - { to_int(FAResult::ABN) , "abn" }, - { to_int(FAResult::NSD) , "nsd" }, - { to_int(FAResult::CarrierIndex) , "carrierindex" }, - { to_int(FAResult::MaxSpurIndex) , "maxspurindex" }, - { to_int(FAResult::AB_Width) , "ab_width" }, - { to_int(FAResult::AB_I1) , "ab_i1" }, - { to_int(FAResult::AB_I2) , "ab_i2" }, - { to_int(FAResult::AB_NBins) , "ab_nbins" }, - { to_int(FAResult::AB_RSS) , "ab_rss" }, - { to_int(FAResult::Signal_NBins) , "signal_nbins" }, - { to_int(FAResult::Signal_RSS) , "signal_rss" }, - { to_int(FAResult::CLK_NBins) , "clk_nbins" }, - { to_int(FAResult::CLK_RSS) , "clk_rss" }, - { to_int(FAResult::HD_NBins) , "hd_nbins" }, - { to_int(FAResult::HD_RSS) , "hd_rss" }, - { to_int(FAResult::ILOS_NBins) , "ilos_nbins" }, - { to_int(FAResult::ILOS_RSS) , "ilos_rss" }, - { to_int(FAResult::ILGT_NBins) , "ilgt_nbins" }, - { to_int(FAResult::ILGT_RSS) , "ilgt_rss" }, - { to_int(FAResult::IMD_NBins) , "imd_nbins" }, - { to_int(FAResult::IMD_RSS) , "imd_rss" }, - { to_int(FAResult::UserDist_NBins) , "userdist_nbins" }, - { to_int(FAResult::UserDist_RSS) , "userdist_rss" }, - { to_int(FAResult::THD_NBins) , "thd_nbins" }, - { to_int(FAResult::THD_RSS) , "thd_rss" }, - { to_int(FAResult::ILV_NBins) , "ilv_nbins" }, - { to_int(FAResult::ILV_RSS) , "ilv_rss" }, - { to_int(FAResult::Dist_NBins) , "dist_nbins" }, - { to_int(FAResult::Dist_RSS) , "dist_rss" }, - { to_int(FAResult::Noise_NBins) , "noise_nbins" }, - { to_int(FAResult::Noise_RSS) , "noise_rss" }, - { to_int(FAResult::NAD_NBins) , "nad_nbins" }, - { to_int(FAResult::NAD_RSS) , "nad_rss" }} - ); - - const enum_map fa_tone_result_map ("FAToneResult", { - { to_int(FAToneResult::OrderIndex) , "orderindex" }, - { to_int(FAToneResult::Tag) , "tag" }, - { to_int(FAToneResult::Freq) , "freq" }, - { to_int(FAToneResult::FFinal) , "ffinal" }, - { to_int(FAToneResult::FWAvg) , "fwavg" }, - { to_int(FAToneResult::I1) , "i1" }, - { to_int(FAToneResult::I2) , "i2" }, - { to_int(FAToneResult::NBins) , "nbins" }, - { to_int(FAToneResult::InBand) , "inband" }, - { to_int(FAToneResult::Mag) , "mag" }, - { to_int(FAToneResult::Mag_dBFS) , "mag_dbfs" }, - { to_int(FAToneResult::Mag_dBc) , "mag_dbc" }, - { to_int(FAToneResult::Phase) , "phase" }, - { to_int(FAToneResult::Phase_c) , "phase_c" }} - ); - - const enum_map object_type_map ("ObjectType", { - { to_int(ObjectType::FourierAnalysis) , "FourierAnalysis" }} - ); - +const enum_map + fa_comp_type_map("FACompType", + { { to_int(FACompType::DC), "DC" }, + { to_int(FACompType::FixedTone), "FixedTone" }, + { to_int(FACompType::MaxTone), "MaxTone" }, + { to_int(FACompType::WOTone), "WOTone" } }); + +const enum_map + fa_result_map("FAResult", + { { to_int(FAResult::AnalysisType), "analysistype" }, + { to_int(FAResult::SignalType), "signaltype" }, + { to_int(FAResult::NFFT), "nfft" }, + { to_int(FAResult::DataSize), "datasize" }, + { to_int(FAResult::FBin), "fbin" }, + { to_int(FAResult::FData), "fdata" }, + { to_int(FAResult::FSample), "fsample" }, + { to_int(FAResult::FShift), "fshift" }, + { to_int(FAResult::FSNR), "fsnr" }, + { to_int(FAResult::SNR), "snr" }, + { to_int(FAResult::SINAD), "sinad" }, + { to_int(FAResult::SFDR), "sfdr" }, + { to_int(FAResult::ABN), "abn" }, + { to_int(FAResult::NSD), "nsd" }, + { to_int(FAResult::CarrierIndex), "carrierindex" }, + { to_int(FAResult::MaxSpurIndex), "maxspurindex" }, + { to_int(FAResult::AB_Width), "ab_width" }, + { to_int(FAResult::AB_I1), "ab_i1" }, + { to_int(FAResult::AB_I2), "ab_i2" }, + { to_int(FAResult::AB_NBins), "ab_nbins" }, + { to_int(FAResult::AB_RSS), "ab_rss" }, + { to_int(FAResult::Signal_NBins), "signal_nbins" }, + { to_int(FAResult::Signal_RSS), "signal_rss" }, + { to_int(FAResult::CLK_NBins), "clk_nbins" }, + { to_int(FAResult::CLK_RSS), "clk_rss" }, + { to_int(FAResult::HD_NBins), "hd_nbins" }, + { to_int(FAResult::HD_RSS), "hd_rss" }, + { to_int(FAResult::ILOS_NBins), "ilos_nbins" }, + { to_int(FAResult::ILOS_RSS), "ilos_rss" }, + { to_int(FAResult::ILGT_NBins), "ilgt_nbins" }, + { to_int(FAResult::ILGT_RSS), "ilgt_rss" }, + { to_int(FAResult::IMD_NBins), "imd_nbins" }, + { to_int(FAResult::IMD_RSS), "imd_rss" }, + { to_int(FAResult::UserDist_NBins), "userdist_nbins" }, + { to_int(FAResult::UserDist_RSS), "userdist_rss" }, + { to_int(FAResult::THD_NBins), "thd_nbins" }, + { to_int(FAResult::THD_RSS), "thd_rss" }, + { to_int(FAResult::ILV_NBins), "ilv_nbins" }, + { to_int(FAResult::ILV_RSS), "ilv_rss" }, + { to_int(FAResult::Dist_NBins), "dist_nbins" }, + { to_int(FAResult::Dist_RSS), "dist_rss" }, + { to_int(FAResult::Noise_NBins), "noise_nbins" }, + { to_int(FAResult::Noise_RSS), "noise_rss" }, + { to_int(FAResult::NAD_NBins), "nad_nbins" }, + { to_int(FAResult::NAD_RSS), "nad_rss" } }); + +const enum_map + fa_tone_result_map("FAToneResult", + { { to_int(FAToneResult::OrderIndex), "orderindex" }, + { to_int(FAToneResult::Tag), "tag" }, + { to_int(FAToneResult::Freq), "freq" }, + { to_int(FAToneResult::FFinal), "ffinal" }, + { to_int(FAToneResult::FWAvg), "fwavg" }, + { to_int(FAToneResult::I1), "i1" }, + { to_int(FAToneResult::I2), "i2" }, + { to_int(FAToneResult::NBins), "nbins" }, + { to_int(FAToneResult::InBand), "inband" }, + { to_int(FAToneResult::Mag), "mag" }, + { to_int(FAToneResult::Mag_dBFS), "mag_dbfs" }, + { to_int(FAToneResult::Mag_dBc), "mag_dbc" }, + { to_int(FAToneResult::Phase), "phase" }, + { to_int(FAToneResult::Phase_c), "phase_c" } }); + +const enum_map object_type_map("ObjectType", + { { to_int(ObjectType::FourierAnalysis), + "FourierAnalysis" } }); + } // namespace genalyzer_impl #endif // GENALYZER_IMPL_ENUM_MAPS_HPP \ No newline at end of file diff --git a/include/enums.hpp b/include/enums.hpp index c56bc1e..96f44c6 100644 --- a/include/enums.hpp +++ b/include/enums.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_ENUMS_HPP #define GENALYZER_IMPL_ENUMS_HPP @@ -6,73 +9,59 @@ */ namespace genalyzer_impl { - enum class AnalysisType : int { - DNL, - Fourier, - Histogram, - INL, - Waveform - }; - - enum class CodeFormat : int { - OffsetBinary, - TwosComplement - }; - - enum class DnlSignal : int { - Ramp, - Tone - }; - - // Noise means not DC and not Signal and not Distortion - enum class FACompTag : int { // Fourier Analysis Component Tag - DC, // DC component (always Bin 0) - Signal, // Signal component - HD, // Harmonic distortion - IMD, // Intermodulation distortion - ILOS, // Interleaving offset component - ILGT, // Interleaving gain/timing/BW component - CLK, // Clock component - UserDist, // User-designated distortion - Noise // Noise component (e.g. WorstOther) - }; - - enum class FASsb : int { - Default, // Default SSB (applies to auto-generated components) - DC, // SSB for DC component - Signal, // SSB for Signal components - WO, // SSB for WorstOther components - }; - - enum class FreqAxisFormat : int { - Bins, - Freq, - Norm - }; - - enum class FreqAxisType : int { - DcCenter, - DcLeft, - Real - }; - - enum class InlLineFit : int { - BestFit, - EndFit, - NoFit - }; - - enum class RfftScale : int { - DbfsDc, // Full-scale sinusoid measures -3 dBFS - DbfsSin, // Full-scale sinusoid measures 0 dBFS - Native // Full-scale sinusoid measures -6 dBFS - }; - - enum class Window : int { - BlackmanHarris, - Hann, - NoWindow - }; +enum class AnalysisType : int { DNL, + Fourier, + Histogram, + INL, + Waveform }; + +enum class CodeFormat : int { OffsetBinary, + TwosComplement }; + +enum class DnlSignal : int { Ramp, + Tone }; + +// Noise means not DC and not Signal and not Distortion +enum class FACompTag : int { // Fourier Analysis Component Tag + DC, // DC component (always Bin 0) + Signal, // Signal component + HD, // Harmonic distortion + IMD, // Intermodulation distortion + ILOS, // Interleaving offset component + ILGT, // Interleaving gain/timing/BW component + CLK, // Clock component + UserDist, // User-designated distortion + Noise // Noise component (e.g. WorstOther) +}; + +enum class FASsb : int { + Default, // Default SSB (applies to auto-generated components) + DC, // SSB for DC component + Signal, // SSB for Signal components + WO, // SSB for WorstOther components +}; + +enum class FreqAxisFormat : int { Bins, + Freq, + Norm }; + +enum class FreqAxisType : int { DcCenter, + DcLeft, + Real }; + +enum class InlLineFit : int { BestFit, + EndFit, + NoFit }; + +enum class RfftScale : int { + DbfsDc, // Full-scale sinusoid measures -3 dBFS + DbfsSin, // Full-scale sinusoid measures 0 dBFS + Native // Full-scale sinusoid measures -6 dBFS +}; + +enum class Window : int { BlackmanHarris, + Hann, + NoWindow }; } // namespace genalyzer_impl @@ -81,98 +70,96 @@ namespace genalyzer_impl { */ namespace genalyzer_impl { - enum class FACompType : int { // Fourier Analysis Component Type - DC, // DC component (always Bin 0) - FixedTone, // Tone with fixed, user-defined location - MaxTone, // Next largest tone - WOTone // Worst other tone - }; - - enum class FAResult : int { // Fourier Analysis Results - // Meta Data - AnalysisType = 0, // Analysis type - SignalType, // Signal type: 0=Real, 1=Cplx - NFFT, // FFT size - DataSize, // Data size - FBin, // Frequency resolution (Hz) - FData, // Data rate (S/s) - FSample, // Sample rate (S/s) - FShift, // Shift frequency (Hz) - // Primary Measurements - FSNR, // Full-Scale-to-Noise ratio, a.k.a "SNRFS" (dB) - SNR, // Signal-to-Noise ratio (dB) - SINAD, // Signal-to-Noise-and-Distortion ratio (dB) - SFDR, // Spurious-Free Dynamic Range (dB) - ABN, // Average Bin Noise (dBFS) - NSD, // Noise Spectral Density (dBFS/Hz) - // Carrier and MaxSpur - CarrierIndex, // Order index of Carrier tone - MaxSpurIndex, // Order index of MaxSpur tone - // Analysis Band Info - AB_Width, // Width (Hz) - AB_I1, // Index 1 - AB_I2, // Index 2 - AB_NBins, // Number of bins - AB_RSS, // Root-sum-square - // In-Band Tag Info - Signal_NBins, - Signal_RSS, - CLK_NBins, - CLK_RSS, - HD_NBins, - HD_RSS, - ILOS_NBins, - ILOS_RSS, - ILGT_NBins, - ILGT_RSS, - IMD_NBins, - IMD_RSS, - UserDist_NBins, - UserDist_RSS, - // In-Band Composite Info - THD_NBins, // HD + IMD (total harmonic distortion) - THD_RSS, - ILV_NBins, // ILOS + ILGT (total interleaving) - ILV_RSS, - Dist_NBins, // Distortion - Dist_RSS, - Noise_NBins, // Noise - Noise_RSS, - NAD_NBins, // Noise + Distortion - NAD_RSS, - // - __SIZE__ - }; - - enum class FAToneResult : int { // Fourier Analysis Tone Results - OrderIndex = 0, - Tag, - Freq, - FFinal, - FWAvg, - I1, - I2, - NBins, - InBand, - Mag, - Mag_dBFS, - Mag_dBc, - Phase, - Phase_c, - // - __SIZE__ - }; - - enum class FPFormat { // Floating-point format - Auto, - Eng, - Fix, - Sci - }; - - enum class ObjectType { - FourierAnalysis - }; +enum class FACompType : int { // Fourier Analysis Component Type + DC, // DC component (always Bin 0) + FixedTone, // Tone with fixed, user-defined location + MaxTone, // Next largest tone + WOTone // Worst other tone +}; + +enum class FAResult : int { // Fourier Analysis Results + // Meta Data + AnalysisType = 0, // Analysis type + SignalType, // Signal type: 0=Real, 1=Cplx + NFFT, // FFT size + DataSize, // Data size + FBin, // Frequency resolution (Hz) + FData, // Data rate (S/s) + FSample, // Sample rate (S/s) + FShift, // Shift frequency (Hz) + // Primary Measurements + FSNR, // Full-Scale-to-Noise ratio, a.k.a "SNRFS" (dB) + SNR, // Signal-to-Noise ratio (dB) + SINAD, // Signal-to-Noise-and-Distortion ratio (dB) + SFDR, // Spurious-Free Dynamic Range (dB) + ABN, // Average Bin Noise (dBFS) + NSD, // Noise Spectral Density (dBFS/Hz) + // Carrier and MaxSpur + CarrierIndex, // Order index of Carrier tone + MaxSpurIndex, // Order index of MaxSpur tone + // Analysis Band Info + AB_Width, // Width (Hz) + AB_I1, // Index 1 + AB_I2, // Index 2 + AB_NBins, // Number of bins + AB_RSS, // Root-sum-square + // In-Band Tag Info + Signal_NBins, + Signal_RSS, + CLK_NBins, + CLK_RSS, + HD_NBins, + HD_RSS, + ILOS_NBins, + ILOS_RSS, + ILGT_NBins, + ILGT_RSS, + IMD_NBins, + IMD_RSS, + UserDist_NBins, + UserDist_RSS, + // In-Band Composite Info + THD_NBins, // HD + IMD (total harmonic distortion) + THD_RSS, + ILV_NBins, // ILOS + ILGT (total interleaving) + ILV_RSS, + Dist_NBins, // Distortion + Dist_RSS, + Noise_NBins, // Noise + Noise_RSS, + NAD_NBins, // Noise + Distortion + NAD_RSS, + // + __SIZE__ +}; + +enum class FAToneResult : int { // Fourier Analysis Tone Results + OrderIndex = 0, + Tag, + Freq, + FFinal, + FWAvg, + I1, + I2, + NBins, + InBand, + Mag, + Mag_dBFS, + Mag_dBc, + Phase, + Phase_c, + // + __SIZE__ +}; + +enum class FPFormat { // Floating-point format + Auto, + Eng, + Fix, + Sci +}; + +enum class ObjectType { FourierAnalysis }; } // namespace genalyzer_impl diff --git a/include/exceptions.hpp b/include/exceptions.hpp index 9eb2006..1170615 100644 --- a/include/exceptions.hpp +++ b/include/exceptions.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_EXCEPTIONS_HPP #define GENALYZER_IMPL_EXCEPTIONS_HPP @@ -5,15 +8,13 @@ namespace genalyzer_impl { - class logic_error final : public std::logic_error - { - using std::logic_error::logic_error; - }; +class logic_error final : public std::logic_error { + using std::logic_error::logic_error; +}; - class runtime_error final : public std::runtime_error - { - using std::runtime_error::runtime_error; - }; +class runtime_error final : public std::runtime_error { + using std::runtime_error::runtime_error; +}; } // namespace genalyzer_impl diff --git a/include/expression.hpp b/include/expression.hpp index 1f95228..0f6d00d 100644 --- a/include/expression.hpp +++ b/include/expression.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_EXPRESSION_HPP #define GENALYZER_IMPL_EXPRESSION_HPP @@ -10,45 +13,41 @@ namespace genalyzer_impl { - struct expression_token; +struct expression_token; - class expression - { - public: +class expression { +public: + using token_ptr = std::unique_ptr; + using token_vector = std::vector; + using var_map = std::map; + using var_set = std::set; - using token_ptr = std::unique_ptr; - using token_vector = std::vector; - using var_map = std::map; - using var_set = std::set; +public: + expression(const str_t &infix_string); - public: + ~expression(); - expression(const str_t& infix_string); +public: + // Returns true if expression depends on one or more variables in vars + bool depends_on(const var_set &vars) const; - ~expression(); - - public: + real_t evaluate(const var_map &vars = var_map()) const; - // Returns true if expression depends on one or more variables in vars - bool depends_on(const var_set& vars) const; + str_t to_postfix_string(FPFormat fmt = FPFormat::Auto, + int max_prec = -1) const; - real_t evaluate(const var_map& vars = var_map()) const; + str_t to_string(FPFormat fmt = FPFormat::Auto, int max_prec = -1) const; - str_t to_postfix_string(FPFormat fmt = FPFormat::Auto, int max_prec = -1) const; - - str_t to_string(FPFormat fmt = FPFormat::Auto, int max_prec = -1) const; + // Returns the variables expression depends on + var_set vars() const; - // Returns the variables expression depends on - var_set vars() const; + // Returns the first expression variable not found in vars + str_t vars_defined(const var_map &vars) const; - // Returns the first expression variable not found in vars - str_t vars_defined(const var_map& vars) const; - - private: +private: + token_vector m_infix_tokens; - token_vector m_infix_tokens; - - }; // class expression +}; // class expression } // namespace genalyzer_impl diff --git a/include/formatted_data.hpp b/include/formatted_data.hpp index 1032b27..70ce826 100644 --- a/include/formatted_data.hpp +++ b/include/formatted_data.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_FORMATTED_DATA_HPP #define GENALYZER_IMPL_FORMATTED_DATA_HPP @@ -5,13 +8,9 @@ namespace genalyzer_impl { - str_t table( - const std::vector& header_rows, - const std::vector& data_rows, - int col_margin, - bool show_border, - bool show_col_sep - ); +str_t table(const std::vector &header_rows, + const std::vector &data_rows, int col_margin, + bool show_border, bool show_col_sep); } // namespace genalyzer_impl diff --git a/include/fourier_analysis.hpp b/include/fourier_analysis.hpp index 0e8d0ae..ae6d446 100644 --- a/include/fourier_analysis.hpp +++ b/include/fourier_analysis.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_FOURIER_ANALYSIS_HPP #define GENALYZER_IMPL_FOURIER_ANALYSIS_HPP @@ -16,215 +19,225 @@ namespace genalyzer_impl { - class fourier_analysis final : public object - { - public: +class fourier_analysis final : public object { +public: + using mask_map = std::map; + using min_max_def_t = std::tuple; + using var_map = expression::var_map; - using mask_map = std::map; - using min_max_def_t = std::tuple; - using var_map = expression::var_map; +public: + static std::shared_ptr create() { + return std::make_shared(); + } - public: + static std::shared_ptr load(const str_t &filename); - static std::shared_ptr create() - { - return std::make_shared(); - } + static const min_max_def_t mmd_hd; + static const min_max_def_t mmd_imd; + static const min_max_def_t mmd_wo; + static const min_max_def_t mmd_ssb; - static std::shared_ptr load(const str_t& filename); +public: // Constructors, Destructor, and Assignment + fourier_analysis(); - static const min_max_def_t mmd_hd; - static const min_max_def_t mmd_imd; - static const min_max_def_t mmd_wo; - static const min_max_def_t mmd_ssb; + fourier_analysis(const fourier_analysis &); - public: // Constructors, Destructor, and Assignment + fourier_analysis(fourier_analysis &&); - fourier_analysis(); + ~fourier_analysis() = default; - fourier_analysis(const fourier_analysis&); + fourier_analysis &operator=(const fourier_analysis &); - fourier_analysis(fourier_analysis&&); + fourier_analysis &operator=(fourier_analysis &&); - ~fourier_analysis() = default; +public: // Analysis + fourier_analysis_results analyze(const real_t *in_data, + const size_t in_size, + const size_t nfft, + FreqAxisType axis_type) const; - fourier_analysis& operator=(const fourier_analysis&); +public: // Component Definition + void add_fixed_tone(const str_t &key, FACompTag tag, const str_t &freq, + int ssb); - fourier_analysis& operator=(fourier_analysis&&); + void add_max_tone(const str_t &key, FACompTag tag, const str_t ¢er, + const str_t &width, int ssb); - public: // Analysis + void remove_comp(const str_t &key); - fourier_analysis_results analyze(const real_t* in_data, const size_t in_size, - const size_t nfft, FreqAxisType axis_type) const; +public: // Configuration Getters + str_t ab_center() const { + return m_ab_center; + } + str_t ab_width() const { + return m_ab_width; + } + std::set clk() const { + return m_clk; + } + str_t fdata() const { + return m_fdata; + } + str_t fsample() const { + return m_fdata; + } + str_t fshift() const { + return m_fdata; + } + int hd() const { + return m_hd; + } + std::set ilv() const { + return m_ilv; + } + int imd() const { + return m_imd; + } + int wo() const { + return m_wo; + } - public: // Component Definition + int ssb(FASsb group) const; - void add_fixed_tone(const str_t& key, FACompTag tag, const str_t& freq, int ssb); +public: // Configuration Setters + void set_analysis_band(const str_t ¢er, const str_t &width); - void add_max_tone(const str_t& key, FACompTag tag, const str_t& center, const str_t& width, int ssb); + void set_clk(const std::set &clk); - void remove_comp(const str_t& key); + void set_fdata(const str_t &expr); - public: // Configuration Getters + void set_fsample(const str_t &expr); - str_t ab_center() const { return m_ab_center; }; - str_t ab_width() const { return m_ab_width; }; - std::set clk() const { return m_clk; }; - str_t fdata() const { return m_fdata; }; - str_t fsample() const { return m_fdata; }; - str_t fshift() const { return m_fdata; }; - int hd() const { return m_hd; }; - std::set ilv() const { return m_ilv; }; - int imd() const { return m_imd; }; - int wo() const { return m_wo; }; + void set_fshift(const str_t &expr); - int ssb(FASsb group) const; + void set_hd(int n); - public: // Configuration Setters + void set_ilv(const std::set &ilv); - void set_analysis_band(const str_t& center, const str_t& width); + void set_imd(int n); - void set_clk(const std::set& clk); + void set_ssb(FASsb group, int ssb); - void set_fdata(const str_t& expr); + void set_var(const str_t &key, real_t x); - void set_fsample(const str_t& expr); + void set_wo(int n); - void set_fshift(const str_t& expr); +public: // Key Queries + static bool is_reserved(const str_t &key); - void set_hd(int n); + static bool is_valid(const str_t &key); - void set_ilv(const std::set& ilv); + bool is_available(const str_t &key) const { + return !is_reserved(key) && !is_comp(key) && !is_var(key) && + is_valid(key); + } - void set_imd(int n); + bool is_comp(const str_t &key) const { + return !(m_user_comps.find(key) == m_user_comps.end()); + } - void set_ssb(FASsb group, int ssb); + bool is_var(const str_t &key) const { + return !(m_user_vars.find(key) == m_user_vars.end()); + } - void set_var(const str_t& key, real_t x); +public: // Other Member Functions + static str_t flat_tone_key(const str_t &key, int result_index); - void set_wo(int n); + static std::pair split_key(const str_t &key); - public: // Key Queries + str_t preview(bool cplx) const; - static bool is_reserved(const str_t& key); + void reset(); - static bool is_valid(const str_t& key); + std::vector result_key_lengths(size_t in_size, + size_t nfft) const; - bool is_available(const str_t& key) const - { - return !is_reserved(key) && !is_comp(key) && !is_var(key) && is_valid(key); - } + size_t results_size(size_t in_size, size_t nfft) const; - bool is_comp(const str_t& key) const - { - return !(m_user_comps.find(key) == m_user_comps.end()); - } +private: + static const str_t key_pattern; + static const str_t wo_pattern; + static const std::set reserved_keys; + static const str_vector reserved_patterns; + static const str_t flat_key_coupler; - bool is_var(const str_t& key) const - { - return !(m_user_vars.find(key) == m_user_vars.end()); - } +private: // Virtual Function Overrides + bool equals_impl(const object &that) const override; - public: // Other Member Functions + ObjectType object_type_impl() const override { + return ObjectType::FourierAnalysis; + } - static str_t flat_tone_key(const str_t& key, int result_index); + void save_impl(const str_t &filename) const override; - static std::pair split_key(const str_t& key); + str_t to_string_impl() const override; - str_t preview(bool cplx) const; +private: + using comp_ptr = std::unique_ptr; + using comp_map = std::map; + using comp_data_t = std::tuple>; - void reset(); + static void add_comp(str_vector &keys, comp_map &comps, const str_t &k, + comp_ptr c); - std::vector result_key_lengths(size_t in_size, size_t nfft) const; + static int limit_ssb(int ssb, int lower_limit); - size_t results_size(size_t in_size, size_t nfft) const; + comp_data_t generate_comps(bool cplx) const; - private: + void if_key_not_available_throw(const str_t &key) const; - static const str_t key_pattern; - static const str_t wo_pattern; - static const std::set reserved_keys; - static const str_vector reserved_patterns; - static const str_t flat_key_coupler; +private: // Analysis and related subroutines + static mask_map initialize_masks(bool cplx, size_t size); - private: // Virtual Function Overrides + fourier_analysis_results analyze_impl( + const real_t *msq_data, // mean-square FFT magnitude data + const size_t msq_size, // size of ms_data + const size_t nfft, // FFT size + FreqAxisType axis_type, // + const cplx_t *fft_data = + nullptr, // complex FFT data; if provided, results include phase + const size_t fft_size = + 0 // size of fft_data; if fft_data is not Null, + ) const; // fft_size should equal msq_size - bool equals_impl(const object& that) const override; + void finalize_masks(mask_map &masks) const; - ObjectType object_type_impl() const override - { - return ObjectType::FourierAnalysis; - } + var_map initialize_vars(size_t nfft) const; - void save_impl(const str_t& filename) const override; + void setup_analysis_band(bool cplx, fourier_analysis_comp_mask &mask, + var_map &vars) const; - str_t to_string_impl() const override; +public: // Public configuration parameters + bool clk_as_noise; // Treat CLK components as noise + bool dc_as_dist; // Treat DC component as distortion + bool en_conv_offset; // Enable converter offset component + bool en_fund_images; // Enable fundamental image component(s) + bool en_quad_errors; // Enable quadrature error tone components + bool ilv_as_noise; // Treat ILV components as noise - private: +private: // Private configuration parameters + int m_hd; // Order of harmonic distortion + int m_imd; // Order of intermodulation distortion + int m_wo; // Number of worst others + int m_ssb_def; // Default SSB (for auto-generated tone components) + int m_ssb_dc; // SSB for DC + int m_ssb_sig; // SSB for Signals + int m_ssb_wo; // SSB for WO + str_t m_ab_center; // Analysis band center + str_t m_ab_width; // Analysis band width + str_t m_fdata; // Data rate + str_t m_fsample; // Sample rate + str_t m_fshift; // Shift frequency (sum of frequency translations after + // sampling) + std::set m_clk; // Clock sub-harmonic divisors + std::set m_ilv; // Interleaving factors - using comp_ptr = std::unique_ptr; - using comp_map = std::map; - using comp_data_t = std::tuple>; + // User-defined components and variables + str_vector m_user_keys; + comp_map m_user_comps; + var_map m_user_vars; - static void add_comp(str_vector& keys, comp_map& comps, const str_t& k, comp_ptr c); - - static int limit_ssb(int ssb, int lower_limit); - - comp_data_t generate_comps(bool cplx) const; - - void if_key_not_available_throw(const str_t& key) const; - - private: // Analysis and related subroutines - - static mask_map initialize_masks(bool cplx, size_t size); - - fourier_analysis_results analyze_impl( - const real_t* msq_data, // mean-square FFT magnitude data - const size_t msq_size, // size of ms_data - const size_t nfft, // FFT size - FreqAxisType axis_type, // - const cplx_t* fft_data = nullptr, // complex FFT data; if provided, results include phase - const size_t fft_size = 0 // size of fft_data; if fft_data is not Null, - ) const; // fft_size should equal msq_size - - void finalize_masks(mask_map& masks) const; - - var_map initialize_vars(size_t nfft) const; - - void setup_analysis_band(bool cplx, fourier_analysis_comp_mask& mask, var_map& vars) const; - - public: // Public configuration parameters - - bool clk_as_noise; // Treat CLK components as noise - bool dc_as_dist; // Treat DC component as distortion - bool en_conv_offset; // Enable converter offset component - bool en_fund_images; // Enable fundamental image component(s) - bool en_quad_errors; // Enable quadrature error tone components - bool ilv_as_noise; // Treat ILV components as noise - - private: // Private configuration parameters - - int m_hd; // Order of harmonic distortion - int m_imd; // Order of intermodulation distortion - int m_wo; // Number of worst others - int m_ssb_def; // Default SSB (for auto-generated tone components) - int m_ssb_dc; // SSB for DC - int m_ssb_sig; // SSB for Signals - int m_ssb_wo; // SSB for WO - str_t m_ab_center; // Analysis band center - str_t m_ab_width; // Analysis band width - str_t m_fdata; // Data rate - str_t m_fsample; // Sample rate - str_t m_fshift; // Shift frequency (sum of frequency translations after sampling) - std::set m_clk; // Clock sub-harmonic divisors - std::set m_ilv; // Interleaving factors - - // User-defined components and variables - str_vector m_user_keys; - comp_map m_user_comps; - var_map m_user_vars; - - }; // class fourier_analysis +}; // class fourier_analysis } // namespace genalyzer_impl diff --git a/include/fourier_analysis_comp_mask.hpp b/include/fourier_analysis_comp_mask.hpp index cd6cd39..cfa8129 100644 --- a/include/fourier_analysis_comp_mask.hpp +++ b/include/fourier_analysis_comp_mask.hpp @@ -1,194 +1,164 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_FOURIER_ANALYSIS_COMP_MASK_HPP #define GENALYZER_IMPL_FOURIER_ANALYSIS_COMP_MASK_HPP -#include #include "type_aliases.hpp" +#include namespace genalyzer_impl { - // Ranges are set as [first, last], i.e., inclusive-inclusive, - // but are stored [first, last+1) like STL, i.e., inclusive-exclusive - class fourier_analysis_comp_mask - { - public: - - enum BoundaryMode { Stop, Wrap }; - - public: - - fourier_analysis_comp_mask(bool cplx, size_t array_size) - : m_mode {cplx ? Wrap : Stop}, - m_ufirst {0}, - m_ulast {array_size - 1}, - m_usize {array_size}, - m_first {0}, - m_last {static_cast(array_size - 1)}, - m_size {static_cast(array_size)}, - m_data {} - {} - - fourier_analysis_comp_mask(bool cplx, size_t array_size, const std::vector& init); - - fourier_analysis_comp_mask(const fourier_analysis_comp_mask& m) - : m_mode {m.m_mode}, - m_ufirst {m.m_ufirst}, - m_ulast {m.m_ulast}, - m_usize {m.m_usize}, - m_first {m.m_first}, - m_last {m.m_last}, - m_size {m.m_size}, - m_data (m.m_data) - {} - - fourier_analysis_comp_mask(fourier_analysis_comp_mask&& m) - : m_mode {m.m_mode}, - m_ufirst {m.m_ufirst}, - m_ulast {m.m_ulast}, - m_usize {m.m_usize}, - m_first {m.m_first}, - m_last {m.m_last}, - m_size {m.m_size}, - m_data (std::move(m.m_data)) - {} - - ~fourier_analysis_comp_mask() = default; - - public: - - fourier_analysis_comp_mask& operator=(const fourier_analysis_comp_mask& m) - { - if (&m != this) { - fourier_analysis_comp_mask the_copy (m); - std::swap(the_copy, *this); - } - return *this; - } - - fourier_analysis_comp_mask& operator=(fourier_analysis_comp_mask&& m) - { - std::swap(this->m_mode , m.m_mode); - std::swap(this->m_ufirst , m.m_ufirst); - std::swap(this->m_ulast , m.m_ulast); - std::swap(this->m_usize , m.m_usize); - std::swap(this->m_first , m.m_first); - std::swap(this->m_last , m.m_last); - std::swap(this->m_size , m.m_size); - std::swap(this->m_data , m.m_data); - return *this; - } - - fourier_analysis_comp_mask& operator&=(fourier_analysis_comp_mask m); - - fourier_analysis_comp_mask& operator|=(const fourier_analysis_comp_mask& m); - - public: - - void clear() - { - m_data.clear(); - } - - // Returns the number of elements in the ranges - size_t count() const; - - real_t count_r() const - { - return static_cast(count()); - } - - const std::vector& data() const - { - return m_data; - } - - bool equals(const fourier_analysis_comp_mask& that) const - { - return (this->m_usize == that.m_usize) && (this->m_data == that.m_data); - } - - // <0> = index of max element (-1 if not found) - // <1> = last contiguous free index to the left - // <2> = last contiguous free index to the right - std::tuple find_max_index(const real_t* data, size_t size) const; - - // Returns Index1, Index2, Number of Bins - std::tuple get_indexes() const; - - void invert(); - - BoundaryMode mode() const - { - return m_mode; - } - - size_t num_ranges() const - { - return m_data.size() / 2; - } - - // Returns true if [left, right] overlaps any ranges - bool overlaps(size_t left, size_t right) const; // inclusive-inclusive - - void set(std::vector init) - { - fourier_analysis_comp_mask new_mask ((Wrap == this->m_mode), this->m_usize, init); - std::swap(new_mask, *this); - } - - void set_all() - { - m_data = {0, m_usize}; - } - - void set_range(diff_t left, diff_t right); // inclusive-inclusive - - size_t size() const - { - return m_usize; - } - - real_t root_sum(const real_t* data, size_t size) const - { - return std::sqrt(sum(data, size)); - } - - // Returns the sum of the data in the ranges - real_t sum(const real_t* data, size_t size) const; - - void unset_ranges(const fourier_analysis_comp_mask& m); - - private: - - // Returns the index of the first element greater than 'value' - size_t get_index(size_t value) const; - - void if_not_compat_then_throw(const fourier_analysis_comp_mask& m); - - // Document the pre-conditions that make this 'safe' - void set_range_safe(size_t left, size_t right); // inclusive-inclusive - - private: - - BoundaryMode m_mode; - size_t m_ufirst; - size_t m_ulast; - size_t m_usize; - diff_t m_first; - diff_t m_last; - diff_t m_size; - std::vector m_data; - - }; // class fourier_analysis_comp_mask +// Ranges are set as [first, last], i.e., inclusive-inclusive, +// but are stored [first, last+1) like STL, i.e., inclusive-exclusive +class fourier_analysis_comp_mask { +public: + enum BoundaryMode { Stop, + Wrap }; + +public: + fourier_analysis_comp_mask(bool cplx, size_t array_size) : + m_mode{ cplx ? Wrap : Stop }, m_ufirst{ 0 }, m_ulast{ array_size - 1 }, m_usize{ array_size }, m_first{ 0 }, m_last{ static_cast(array_size - 1) }, m_size{ static_cast(array_size) }, m_data{} { + } + + fourier_analysis_comp_mask(bool cplx, size_t array_size, + const std::vector &init); + + fourier_analysis_comp_mask(const fourier_analysis_comp_mask &m) : + m_mode{ m.m_mode }, m_ufirst{ m.m_ufirst }, m_ulast{ m.m_ulast }, m_usize{ m.m_usize }, m_first{ m.m_first }, m_last{ m.m_last }, m_size{ m.m_size }, m_data(m.m_data) { + } + + fourier_analysis_comp_mask(fourier_analysis_comp_mask &&m) : + m_mode{ m.m_mode }, m_ufirst{ m.m_ufirst }, m_ulast{ m.m_ulast }, m_usize{ m.m_usize }, m_first{ m.m_first }, m_last{ m.m_last }, m_size{ m.m_size }, m_data(std::move(m.m_data)) { + } + + ~fourier_analysis_comp_mask() = default; + +public: + fourier_analysis_comp_mask & + operator=(const fourier_analysis_comp_mask &m) { + if (&m != this) { + fourier_analysis_comp_mask the_copy(m); + std::swap(the_copy, *this); + } + return *this; + } + + fourier_analysis_comp_mask &operator=(fourier_analysis_comp_mask &&m) { + std::swap(this->m_mode, m.m_mode); + std::swap(this->m_ufirst, m.m_ufirst); + std::swap(this->m_ulast, m.m_ulast); + std::swap(this->m_usize, m.m_usize); + std::swap(this->m_first, m.m_first); + std::swap(this->m_last, m.m_last); + std::swap(this->m_size, m.m_size); + std::swap(this->m_data, m.m_data); + return *this; + } + + fourier_analysis_comp_mask &operator&=(fourier_analysis_comp_mask m); + + fourier_analysis_comp_mask & + operator|=(const fourier_analysis_comp_mask &m); + +public: + void clear() { + m_data.clear(); + } + + // Returns the number of elements in the ranges + size_t count() const; + + real_t count_r() const { + return static_cast(count()); + } + + const std::vector &data() const { + return m_data; + } + + bool equals(const fourier_analysis_comp_mask &that) const { + return (this->m_usize == that.m_usize) && + (this->m_data == that.m_data); + } + + // <0> = index of max element (-1 if not found) + // <1> = last contiguous free index to the left + // <2> = last contiguous free index to the right + std::tuple find_max_index(const real_t *data, + size_t size) const; + + // Returns Index1, Index2, Number of Bins + std::tuple get_indexes() const; + + void invert(); + + BoundaryMode mode() const { + return m_mode; + } + + size_t num_ranges() const { + return m_data.size() / 2; + } + + // Returns true if [left, right] overlaps any ranges + bool overlaps(size_t left, size_t right) const; // inclusive-inclusive + + void set(std::vector init) { + fourier_analysis_comp_mask new_mask((Wrap == this->m_mode), + this->m_usize, init); + std::swap(new_mask, *this); + } + + void set_all() { + m_data = { 0, m_usize }; + } + + void set_range(diff_t left, diff_t right); // inclusive-inclusive + + size_t size() const { + return m_usize; + } + + real_t root_sum(const real_t *data, size_t size) const { + return std::sqrt(sum(data, size)); + } + + // Returns the sum of the data in the ranges + real_t sum(const real_t *data, size_t size) const; + + void unset_ranges(const fourier_analysis_comp_mask &m); + +private: + // Returns the index of the first element greater than 'value' + size_t get_index(size_t value) const; + + void if_not_compat_then_throw(const fourier_analysis_comp_mask &m); + + // Document the pre-conditions that make this 'safe' + void set_range_safe(size_t left, size_t right); // inclusive-inclusive + +private: + BoundaryMode m_mode; + size_t m_ufirst; + size_t m_ulast; + size_t m_usize; + diff_t m_first; + diff_t m_last; + diff_t m_size; + std::vector m_data; + +}; // class fourier_analysis_comp_mask - inline bool operator==(const fourier_analysis_comp_mask& a, const fourier_analysis_comp_mask& b) - { - return a.equals(b); - } +inline bool operator==(const fourier_analysis_comp_mask &a, + const fourier_analysis_comp_mask &b) { + return a.equals(b); +} - inline bool operator!=(const fourier_analysis_comp_mask& a, const fourier_analysis_comp_mask& b) - { - return !a.equals(b); - } +inline bool operator!=(const fourier_analysis_comp_mask &a, + const fourier_analysis_comp_mask &b) { + return !a.equals(b); +} } // namespace genalyzer_impl diff --git a/include/fourier_analysis_component.hpp b/include/fourier_analysis_component.hpp index db4f56c..28ee181 100644 --- a/include/fourier_analysis_component.hpp +++ b/include/fourier_analysis_component.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_FOURIER_ANALYSIS_COMPONENT_HPP #define GENALYZER_IMPL_FOURIER_ANALYSIS_COMPONENT_HPP @@ -8,214 +11,190 @@ namespace genalyzer_impl { - struct fourier_analysis_component - { - using pointer = std::unique_ptr; - - fourier_analysis_component(FACompType _type, FACompTag _tag) - : type (_type), - tag (_tag) - {} - - virtual ~fourier_analysis_component() = default; - - pointer clone() const - { - return clone_impl(); - } - - bool equals(const fourier_analysis_component& that) const - { - return this->equals_impl(that); - } - - str_t spec() const - { - return spec_impl(); - } - - const FACompType type; - const FACompTag tag; - - private: - - virtual pointer clone_impl() const = 0; - - virtual bool equals_impl(const fourier_analysis_component& that) const = 0; - - virtual str_t spec_impl() const = 0; - - }; // class fourier_analysis_component - - struct fa_dc final : public fourier_analysis_component - { - static pointer create(int ssb) - { - return std::make_unique(ssb); - } - - fa_dc(int _ssb) - : fourier_analysis_component(FACompType::DC, FACompTag::DC), - ssb (_ssb) - {} - - ~fa_dc() = default; - - const int ssb; - - private: - - pointer clone_impl() const override - { - return std::make_unique(*this); - } - - bool equals_impl(const fourier_analysis_component& that_obj) const override - { - bool equal = (this->type == that_obj.type) && (this->tag == that_obj.tag); - if (!equal) { - return false; - } - auto& that = static_cast(that_obj); - return this->ssb == that.ssb; - } - - str_t spec_impl() const override - { - return "SSB= " + std::to_string(ssb); - } - - }; // class fa_dc - - struct fa_fixed_tone final : public fourier_analysis_component - { - static pointer create(FACompTag tag, const str_t& freq, int ssb) - { - return std::make_unique(tag, freq, ssb); - } - - fa_fixed_tone(FACompTag tag, const str_t& _freq, int _ssb) - : fourier_analysis_component(FACompType::FixedTone, tag), - freq (_freq), - ssb (_ssb) - {} - - ~fa_fixed_tone() = default; - - const str_t freq; - const int ssb; - - private: - - pointer clone_impl() const override - { - return std::make_unique(*this); - } - - bool equals_impl(const fourier_analysis_component& that_obj) const override - { - bool equal = (this->type == that_obj.type) && (this->tag == that_obj.tag); - if (!equal) { - return false; - } - auto& that = static_cast(that_obj); - return (this->freq == that.freq) && (this->ssb == that.ssb); - } - - str_t spec_impl() const override - { - return "F= " + freq + " , SSB= " + std::to_string(ssb); - } - - }; // class fa_fixed_tone - - struct fa_max_tone final : public fourier_analysis_component - { - static pointer create(FACompTag tag, const str_t& center, const str_t& width, int ssb) - { - return std::make_unique(tag, center, width, ssb); - } - - fa_max_tone(FACompTag tag, const str_t& _center, const str_t& _width, int _ssb) - : fourier_analysis_component(FACompType::MaxTone, tag), - center (_center), - width (_width), - ssb (_ssb) - {} - - ~fa_max_tone() = default; - - const str_t center; - const str_t width; - const int ssb; - - private: - - pointer clone_impl() const override - { - return std::make_unique(*this); - } - - bool equals_impl(const fourier_analysis_component& that_obj) const override - { - bool equal = (this->type == that_obj.type) && (this->tag == that_obj.tag); - if (!equal) { - return false; - } - auto& that = static_cast(that_obj); - return (this->center == that.center) && - (this->width == that.width ) && - (this->ssb == that.ssb ); - } - - str_t spec_impl() const override - { - // May implement search band in the future. - // return "C= " + center + " , W= " + width + " , SSB= " + std::to_string(ssb); - return "SSB= " + std::to_string(ssb); - } - - }; // class fa_max_tone - - struct fa_wo_tone final : public fourier_analysis_component - { - static pointer create(int ssb) - { - return std::make_unique(ssb); - } - - fa_wo_tone(int _ssb) - : fourier_analysis_component(FACompType::WOTone, FACompTag::Noise), - ssb (_ssb) - {} - - ~fa_wo_tone() = default; - - const int ssb; - - private: - - pointer clone_impl() const override - { - return std::make_unique(*this); - } - - bool equals_impl(const fourier_analysis_component& that_obj) const override - { - bool equal = (this->type == that_obj.type) && (this->tag == that_obj.tag); - if (!equal) { - return false; - } - auto& that = static_cast(that_obj); - return this->ssb == that.ssb; - } - - str_t spec_impl() const override - { - return "SSB= " + std::to_string(ssb); - } - - }; // class fa_wo_tone +struct fourier_analysis_component { + using pointer = std::unique_ptr; + + fourier_analysis_component(FACompType _type, FACompTag _tag) : + type(_type), tag(_tag) { + } + + virtual ~fourier_analysis_component() = default; + + pointer clone() const { + return clone_impl(); + } + + bool equals(const fourier_analysis_component &that) const { + return this->equals_impl(that); + } + + str_t spec() const { + return spec_impl(); + } + + const FACompType type; + const FACompTag tag; + +private: + virtual pointer clone_impl() const = 0; + + virtual bool + equals_impl(const fourier_analysis_component &that) const = 0; + + virtual str_t spec_impl() const = 0; + +}; // class fourier_analysis_component + +struct fa_dc final : public fourier_analysis_component { + static pointer create(int ssb) { + return std::make_unique(ssb); + } + + fa_dc(int _ssb) : + fourier_analysis_component(FACompType::DC, FACompTag::DC), ssb(_ssb) { + } + + ~fa_dc() = default; + + const int ssb; + +private: + pointer clone_impl() const override { + return std::make_unique(*this); + } + + bool + equals_impl(const fourier_analysis_component &that_obj) const override { + bool equal = (this->type == that_obj.type) && + (this->tag == that_obj.tag); + if (!equal) { + return false; + } + auto &that = static_cast(that_obj); + return this->ssb == that.ssb; + } + + str_t spec_impl() const override { + return "SSB= " + std::to_string(ssb); + } + +}; // class fa_dc + +struct fa_fixed_tone final : public fourier_analysis_component { + static pointer create(FACompTag tag, const str_t &freq, int ssb) { + return std::make_unique(tag, freq, ssb); + } + + fa_fixed_tone(FACompTag tag, const str_t &_freq, int _ssb) : + fourier_analysis_component(FACompType::FixedTone, tag), freq(_freq), ssb(_ssb) { + } + + ~fa_fixed_tone() = default; + + const str_t freq; + const int ssb; + +private: + pointer clone_impl() const override { + return std::make_unique(*this); + } + + bool + equals_impl(const fourier_analysis_component &that_obj) const override { + bool equal = (this->type == that_obj.type) && + (this->tag == that_obj.tag); + if (!equal) { + return false; + } + auto &that = static_cast(that_obj); + return (this->freq == that.freq) && (this->ssb == that.ssb); + } + + str_t spec_impl() const override { + return "F= " + freq + " , SSB= " + std::to_string(ssb); + } + +}; // class fa_fixed_tone + +struct fa_max_tone final : public fourier_analysis_component { + static pointer create(FACompTag tag, const str_t ¢er, + const str_t &width, int ssb) { + return std::make_unique(tag, center, width, ssb); + } + + fa_max_tone(FACompTag tag, const str_t &_center, const str_t &_width, + int _ssb) : + fourier_analysis_component(FACompType::MaxTone, tag), center(_center), width(_width), ssb(_ssb) { + } + + ~fa_max_tone() = default; + + const str_t center; + const str_t width; + const int ssb; + +private: + pointer clone_impl() const override { + return std::make_unique(*this); + } + + bool + equals_impl(const fourier_analysis_component &that_obj) const override { + bool equal = (this->type == that_obj.type) && + (this->tag == that_obj.tag); + if (!equal) { + return false; + } + auto &that = static_cast(that_obj); + return (this->center == that.center) && + (this->width == that.width) && (this->ssb == that.ssb); + } + + str_t spec_impl() const override { + // May implement search band in the future. + // return "C= " + center + " , W= " + width + " , SSB= " + + // std::to_string(ssb); + return "SSB= " + std::to_string(ssb); + } + +}; // class fa_max_tone + +struct fa_wo_tone final : public fourier_analysis_component { + static pointer create(int ssb) { + return std::make_unique(ssb); + } + + fa_wo_tone(int _ssb) : + fourier_analysis_component(FACompType::WOTone, + FACompTag::Noise), + ssb(_ssb) { + } + + ~fa_wo_tone() = default; + + const int ssb; + +private: + pointer clone_impl() const override { + return std::make_unique(*this); + } + + bool + equals_impl(const fourier_analysis_component &that_obj) const override { + bool equal = (this->type == that_obj.type) && + (this->tag == that_obj.tag); + if (!equal) { + return false; + } + auto &that = static_cast(that_obj); + return this->ssb == that.ssb; + } + + str_t spec_impl() const override { + return "SSB= " + std::to_string(ssb); + } + +}; // class fa_wo_tone } // namespace genalyzer_impl diff --git a/include/fourier_analysis_results.hpp b/include/fourier_analysis_results.hpp index adf48b6..4146fb9 100644 --- a/include/fourier_analysis_results.hpp +++ b/include/fourier_analysis_results.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_FOURIER_ANALYSIS_RESULTS_HPP #define GENALYZER_IMPL_FOURIER_ANALYSIS_RESULTS_HPP @@ -9,84 +12,77 @@ namespace genalyzer_impl { - struct fa_tone_results - { - real_t get(FAToneResult key) const - { - if (results.find(key) == results.end()) { - throw runtime_error("fa_tone_results::get : key not found"); - } - return results.at(key); - } +struct fa_tone_results { + real_t get(FAToneResult key) const { + if (results.find(key) == results.end()) { + throw runtime_error( + "fa_tone_results::get : key not found"); + } + return results.at(key); + } - void set(FAToneResult key, real_t value) - { - results[key] = value; - if (FAToneResult::I1 == key) { - i1 = static_cast(value); - } else if (FAToneResult::I2 == key) { - i2 = static_cast(value); - } else if (FAToneResult::NBins == key) { - nbins = static_cast(value); - } else if (FAToneResult::InBand == key) { - inband = static_cast(value); - } - } + void set(FAToneResult key, real_t value) { + results[key] = value; + if (FAToneResult::I1 == key) { + i1 = static_cast(value); + } else if (FAToneResult::I2 == key) { + i2 = static_cast(value); + } else if (FAToneResult::NBins == key) { + nbins = static_cast(value); + } else if (FAToneResult::InBand == key) { + inband = static_cast(value); + } + } - void set_mag(real_t ms_value) - { - results[FAToneResult::Mag] = std::sqrt(ms_value); - results[FAToneResult::Mag_dBFS] = bounded_db10(ms_value); - } + void set_mag(real_t ms_value) { + results[FAToneResult::Mag] = std::sqrt(ms_value); + results[FAToneResult::Mag_dBFS] = bounded_db10(ms_value); + } - std::map results; - size_t i1; - size_t i2; - size_t nbins; - bool inband; - }; + std::map results; + size_t i1; + size_t i2; + size_t nbins; + bool inband; +}; - struct fourier_analysis_results - { - real_t get(FAResult key) const - { - if (results.find(key) == results.end()) { - throw runtime_error("fourier_analysis_results::get : key not found"); - } - return results.at(key); - } +struct fourier_analysis_results { + real_t get(FAResult key) const { + if (results.find(key) == results.end()) { + throw runtime_error( + "fourier_analysis_results::get : key not found"); + } + return results.at(key); + } - void set(FAResult key, real_t value) - { - results[key] = value; - } + void set(FAResult key, real_t value) { + results[key] = value; + } - bool contains_tone(const str_t& key) const - { - return tone_results.find(key) != tone_results.end(); - } + bool contains_tone(const str_t &key) const { + return tone_results.find(key) != tone_results.end(); + } - void add_tone(const str_t& key, fa_tone_results tr) - { - if (!contains_tone(key)) { - tone_keys.push_back(key); - tone_results.emplace(key, std::move(tr)); - } - } + void add_tone(const str_t &key, fa_tone_results tr) { + if (!contains_tone(key)) { + tone_keys.push_back(key); + tone_results.emplace(key, std::move(tr)); + } + } - const fa_tone_results& get_tone(const str_t& key) const - { - if (contains_tone(key)) { - return tone_results.at(key); - } else { - throw runtime_error("fourier_analysis_results::get_tone : key not found"); - } - } + const fa_tone_results &get_tone(const str_t &key) const { + if (contains_tone(key)) { + return tone_results.at(key); + } else { + throw runtime_error( + "fourier_analysis_results::get_tone : key not found"); + } + } - std::map results; - str_vector tone_keys; - std::map tone_results; - }; + std::map results; + str_vector tone_keys; + std::map tone_results; +}; } // namespace genalyzer_impl diff --git a/include/fourier_transforms.hpp b/include/fourier_transforms.hpp index 951a50e..7dbbc18 100644 --- a/include/fourier_transforms.hpp +++ b/include/fourier_transforms.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_FOURIER_TRANSFORMS_HPP #define GENALYZER_IMPL_FOURIER_TRANSFORMS_HPP @@ -6,61 +9,27 @@ namespace genalyzer_impl { - void fft( - const real_t* i_data, - size_t i_size, - const real_t* q_data, - size_t q_size, - real_t* out_data, - size_t out_size, - size_t navg, - size_t nfft, - Window window - ); +void fft(const real_t *i_data, size_t i_size, const real_t *q_data, + size_t q_size, real_t *out_data, size_t out_size, size_t navg, + size_t nfft, Window window); - template - void fft( - const T* i_data, - size_t i_size, - const T* q_data, - size_t q_size, - real_t* out_data, - size_t out_size, - int n, - size_t navg, - size_t nfft, - Window window, - CodeFormat format - ); +template +void fft(const T *i_data, size_t i_size, const T *q_data, size_t q_size, + real_t *out_data, size_t out_size, int n, size_t navg, size_t nfft, + Window window, CodeFormat format); - size_t fft_size(size_t i_size, size_t q_size, size_t& navg, size_t& nfft); +size_t fft_size(size_t i_size, size_t q_size, size_t &navg, size_t &nfft); - void rfft( - const real_t* in_data, - size_t in_size, - real_t* out_data, - size_t out_size, - size_t navg, - size_t nfft, - Window window, - RfftScale scale - ); +void rfft(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size, size_t navg, size_t nfft, Window window, + RfftScale scale); - template - void rfft( - const T* in_data, - size_t in_size, - real_t* out_data, - size_t out_size, - int n, - size_t navg, - size_t nfft, - Window window, - CodeFormat format, - RfftScale scale - ); +template +void rfft(const T *in_data, size_t in_size, real_t *out_data, size_t out_size, + int n, size_t navg, size_t nfft, Window window, CodeFormat format, + RfftScale scale); - size_t rfft_size(size_t in_size, size_t& navg, size_t& nfft); +size_t rfft_size(size_t in_size, size_t &navg, size_t &nfft); } // namespace genalyzer_impl diff --git a/include/fourier_utilities.hpp b/include/fourier_utilities.hpp index 8498a94..f62c3a6 100644 --- a/include/fourier_utilities.hpp +++ b/include/fourier_utilities.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_FOURIER_UTILITIES_HPP #define GENALYZER_IMPL_FOURIER_UTILITIES_HPP @@ -6,24 +9,20 @@ namespace genalyzer_impl { - real_t alias(real_t fs, real_t freq, FreqAxisType axis_type); +real_t alias(real_t fs, real_t freq, FreqAxisType axis_type); - real_t coherent(size_t nfft, real_t fs, real_t freq); +real_t coherent(size_t nfft, real_t fs, real_t freq); - void fftshift(const real_t* in_data, size_t in_size, real_t* out_data, size_t out_size); +void fftshift(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size); - void freq_axis( - real_t* data, - size_t size, - size_t nfft, - FreqAxisType axis_type, - real_t fs, - FreqAxisFormat axis_format - ); +void freq_axis(real_t *data, size_t size, size_t nfft, FreqAxisType axis_type, + real_t fs, FreqAxisFormat axis_format); - void ifftshift(const real_t* in_data, size_t in_size, real_t* out_data, size_t out_size); +void ifftshift(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size); - size_t freq_axis_size(size_t nfft, FreqAxisType axis_type); +size_t freq_axis_size(size_t nfft, FreqAxisType axis_type); } // namespace genalyzer_impl diff --git a/include/manager.hpp b/include/manager.hpp index f1d8883..dbbc58c 100644 --- a/include/manager.hpp +++ b/include/manager.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_MANAGER_HPP #define GENALYZER_IMPL_MANAGER_HPP @@ -10,21 +13,21 @@ */ namespace genalyzer_impl::manager { - void clear(); +void clear(); - bool contains(const str_t& key, bool throw_if_not_found = false); +bool contains(const str_t &key, bool throw_if_not_found = false); - bool equal(const str_t& key1, const str_t& key2); +bool equal(const str_t &key1, const str_t &key2); - void remove(const str_t& key); +void remove(const str_t &key); - str_t save(const str_t& key, const str_t& filename = ""); +str_t save(const str_t &key, const str_t &filename = ""); - size_t size(); +size_t size(); - str_t to_string(const str_t& key = ""); +str_t to_string(const str_t &key = ""); - str_t type_str(const str_t& key); +str_t type_str(const str_t &key); } // namespace genalyzer_impl::manager @@ -33,15 +36,15 @@ namespace genalyzer_impl::manager { */ namespace genalyzer_impl::manager { - static const str_t key_pattern = "[[:alpha:]][[:alnum:]._]*"; +static const str_t key_pattern = "[[:alpha:]][[:alnum:]._]*"; - void add_object(const str_t& key, object::pointer obj, bool replace); +void add_object(const str_t &key, object::pointer obj, bool replace); - str_t get_filename_from_object_key(const str_t& key, str_t filename); +str_t get_filename_from_object_key(const str_t &key, str_t filename); - object::pointer get_object(const str_t& key); +object::pointer get_object(const str_t &key); - ObjectType type(const str_t& key); +ObjectType type(const str_t &key); } // namespace genalyzer_impl::manager diff --git a/include/object.hpp b/include/object.hpp index 4489d18..5d2be5a 100644 --- a/include/object.hpp +++ b/include/object.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_OBJECT_HPP #define GENALYZER_IMPL_OBJECT_HPP @@ -8,49 +11,40 @@ namespace genalyzer_impl { - class object - { - public: +class object { +public: + using pointer = std::shared_ptr; - using pointer = std::shared_ptr; +public: + virtual ~object() = default; - public: +public: + bool equals(const object &that) const { + return this->equals_impl(that); + } - virtual ~object() = default; + ObjectType object_type() const { + return object_type_impl(); + } - public: + void save(const str_t &filename) const { + save_impl(filename); + } - bool equals(const object& that) const - { - return this->equals_impl(that); - } + str_t to_string() const { + return to_string_impl(); + } - ObjectType object_type() const - { - return object_type_impl(); - } +private: + virtual bool equals_impl(const object &that) const = 0; - void save(const str_t& filename) const - { - save_impl(filename); - } + virtual ObjectType object_type_impl() const = 0; - str_t to_string() const - { - return to_string_impl(); - } + virtual void save_impl(const str_t &filename) const = 0; - private: + virtual str_t to_string_impl() const = 0; - virtual bool equals_impl(const object& that) const = 0; - - virtual ObjectType object_type_impl() const = 0; - - virtual void save_impl(const str_t& filename) const = 0; - - virtual str_t to_string_impl() const = 0; - - }; // class object +}; // class object } // namespace genalyzer_impl diff --git a/include/processes.hpp b/include/processes.hpp index 2703c64..4561cfe 100644 --- a/include/processes.hpp +++ b/include/processes.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_PROCESSES_HPP #define GENALYZER_IMPL_PROCESSES_HPP @@ -5,76 +8,35 @@ #include "type_aliases.hpp" namespace genalyzer_impl { - - template - void downsample( - const T* in_data, - size_t in_size, - T* out_data, - size_t out_size, - int ratio, - bool interleaved - ); - size_t downsample_size(size_t in_size, int ratio, bool interleaved); +template +void downsample(const T *in_data, size_t in_size, T *out_data, size_t out_size, + int ratio, bool interleaved); - void fshift( - const real_t* i_data, - size_t i_size, - const real_t* q_data, - size_t q_size, - real_t* out_data, - size_t out_size, - real_t fs, - real_t _fshift - ); - - template - void fshift( - const T* i_data, - size_t i_size, - const T* q_data, - size_t q_size, - T* out_data, - size_t out_size, - int n, - real_t fs, - real_t _fshift, - CodeFormat format - ); - - size_t fshift_size(size_t i_size, size_t q_size); - - template - void normalize( - const T* in_data, - size_t in_size, - real_t* out_data, - size_t out_size, - int n, - CodeFormat format - ); - - void polyval( - const real_t* in_data, - size_t in_size, - real_t* out_data, - size_t out_size, - const real_t* c_data, - size_t c_size - ); - - template - void quantize( - const real_t* in_data, - size_t in_size, - T* out_data, - size_t out_size, - real_t fsr, - int n, - real_t noise, - CodeFormat format - ); +size_t downsample_size(size_t in_size, int ratio, bool interleaved); + +void fshift(const real_t *i_data, size_t i_size, const real_t *q_data, + size_t q_size, real_t *out_data, size_t out_size, real_t fs, + real_t _fshift); + +template +void fshift(const T *i_data, size_t i_size, const T *q_data, size_t q_size, + T *out_data, size_t out_size, int n, real_t fs, real_t _fshift, + CodeFormat format); + +size_t fshift_size(size_t i_size, size_t q_size); + +template +void normalize(const T *in_data, size_t in_size, real_t *out_data, + size_t out_size, int n, CodeFormat format); + +void polyval(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size, const real_t *c_data, size_t c_size); + +template +void quantize(const real_t *in_data, size_t in_size, T *out_data, + size_t out_size, real_t fsr, int n, real_t noise, + CodeFormat format); } // namespace genalyzer_impl diff --git a/include/reductions.hpp b/include/reductions.hpp index f6af07b..7bb6ad8 100644 --- a/include/reductions.hpp +++ b/include/reductions.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_REDUCTIONS_HPP #define GENALYZER_IMPL_REDUCTIONS_HPP @@ -7,54 +10,46 @@ namespace genalyzer_impl { - struct std_reduce_t - { - std_reduce_t(size_t size) - : min {0.0}, - max {0.0}, - sum {0.0}, - sumsq {0.0}, - min_index {size}, - max_index {size} - {} - real_t min; - real_t max; - real_t sum; - real_t sumsq; - size_t min_index; - size_t max_index; - }; +struct std_reduce_t { + std_reduce_t(size_t size) : + min{ 0.0 }, max{ 0.0 }, sum{ 0.0 }, sumsq{ 0.0 }, min_index{ size }, max_index{ size } { + } + real_t min; + real_t max; + real_t sum; + real_t sumsq; + size_t min_index; + size_t max_index; +}; - template - std_reduce_t std_reduce( - const T* data, // pointer to array - const size_t size, // array size - const size_t i1, // index of first element - const size_t i2 // one past the last element - ) - { - std_reduce_t r (size); - if (i1 < i2 && i2 <= size) { - r.min = static_cast(data[i1]); - r.max = static_cast(data[i1]); - r.min_index = i1; - r.max_index = i1; - for (size_t i = i1 + 1; i < i2; ++i) { - const real_t x = static_cast(data[i]); - if (x < r.min) { - r.min = x; - r.min_index = i; - } - if (r.max < x) { - r.max = x; - r.max_index = i; - } - r.sum += x; - r.sumsq += x * x; - } - } - return r; - } +template +std_reduce_t std_reduce(const T *data, // pointer to array + const size_t size, // array size + const size_t i1, // index of first element + const size_t i2 // one past the last element +) { + std_reduce_t r(size); + if (i1 < i2 && i2 <= size) { + r.min = static_cast(data[i1]); + r.max = static_cast(data[i1]); + r.min_index = i1; + r.max_index = i1; + for (size_t i = i1 + 1; i < i2; ++i) { + const real_t x = static_cast(data[i]); + if (x < r.min) { + r.min = x; + r.min_index = i; + } + if (r.max < x) { + r.max = x; + r.max_index = i; + } + r.sum += x; + r.sumsq += x * x; + } + } + return r; +} } // namespace genalyzer_impl diff --git a/include/type_aliases.hpp b/include/type_aliases.hpp index fd0de4d..605e8f2 100644 --- a/include/type_aliases.hpp +++ b/include/type_aliases.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_TYPE_ALIASES_HPP #define GENALYZER_IMPL_TYPE_ALIASES_HPP @@ -10,25 +13,25 @@ namespace genalyzer_impl { - using diff_t = std::ptrdiff_t; - using size_t = std::size_t; - using int16_t = std::int_least16_t; - using int32_t = std::int_least32_t; - using int64_t = std::int_least64_t; - using uint16_t = std::uint_least16_t; - using uint32_t = std::uint_least32_t; - using uint64_t = std::uint_least64_t; - using real_t = double; - using cplx_t = std::complex; - using str_t = std::string; +using diff_t = std::ptrdiff_t; +using size_t = std::size_t; +using int16_t = std::int_least16_t; +using int32_t = std::int_least32_t; +using int64_t = std::int_least64_t; +using uint16_t = std::uint_least16_t; +using uint32_t = std::uint_least32_t; +using uint64_t = std::uint_least64_t; +using real_t = double; +using cplx_t = std::complex; +using str_t = std::string; - // pairs - using diff_p = std::pair; - using size_p = std::pair; - using real_p = std::pair; +// pairs +using diff_p = std::pair; +using size_p = std::pair; +using real_p = std::pair; - // vectors - using str_vector = std::vector; +// vectors +using str_vector = std::vector; } // namespace genalyzer_impl diff --git a/include/utils.hpp b/include/utils.hpp index 4e0a6d9..6541bb5 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_UTILS_HPP #define GENALYZER_IMPL_UTILS_HPP @@ -13,143 +16,131 @@ namespace genalyzer_impl { - inline real_t bounded_db10(real_t msq_value) - { - return 10 * std::log10(std::clamp(msq_value, k_abs_min_msq, k_abs_max_msq)); - } - - inline real_t bounded_db20(real_t rms_value) - { - return 20 * std::log10(std::clamp(rms_value, k_abs_min_rms, k_abs_max_rms)); - } - - inline real_t bounded_db(const cplx_t& cplx_value) - { - return bounded_db10(std::norm(cplx_value)); - } - - template - bool is_even(T n) - { - return 0 == n % 2; - } - - template - bool is_odd(T n) - { - return 1 == n % 2; - } - - template - bool is_pow2(T n) - { - return (n < 1) ? false : (0 == (n & (n - 1))); - } - - template - int to_int(E e) - { - static_assert(std::is_enum_v, "Requires enum type"); - return static_cast(e); - } - - template - void assert_eq(const char* trace, const char* name1, T val1, const char* name2, T val2) - { - if (val1 != val2) { - throw runtime_error(str_t(trace) + name1 + " != " + name2); - } - } - - template - void assert_gt0(const char* trace, const char* name, T val) - { - if (!(static_cast(0) < val)) { - throw runtime_error(str_t(trace) + name + " <= 0"); - } - } - - template - void assert_ptr_not_null(const char* trace, const char* name, const T* p) - { - if (nullptr == p) { - throw runtime_error(str_t(trace) + "pointer to " + name + " is NULL"); - } - } - - template - void check_array( - const char* trace, const char* name, const T* p, size_t size, bool interleaved = false) - { - assert_ptr_not_null(trace, name, p); - str_t n = str_t(name) + " size"; - assert_gt0(trace, n.c_str(), size); - if (interleaved && is_odd(size)) { - throw runtime_error(str_t(trace) + " must be even if interleaved"); - } - } - - template - void check_array_pair( - const char* trace, - const char* name1, - const T1* p1, - size_t size1, - const char* name2, - const T2* p2, - size_t size2, - bool interleaved = false - ) - { - check_array(trace, name1, p1, size1); - check_array(trace, name2, p2, size2); - str_t n1 = str_t(name1) + " size"; - str_t n2 = str_t(name2) + " size"; - assert_eq(trace, n1.c_str(), size1, n2.c_str(), size2); - if (interleaved && is_odd(size1)) { - throw runtime_error(str_t(trace) + " must be even if interleaved"); - } - } - - inline void check_code_width(const char* trace, int n) - { - if (n < k_abs_min_code_width || k_abs_max_code_width < n) { - throw runtime_error(str_t(trace) + "resolution outside absolute code width limits : [" - + std::to_string(k_abs_min_code_width) + ", " - + std::to_string(k_abs_max_code_width) + "]"); - } - } - - template - T check_type_absolute_value(const char* trace, int64_t n) - { - static_assert(sizeof(T) <= sizeof(int64_t), "T is bigger than int64_t"); - static_assert(std::is_signed_v, "T must be signed"); - constexpr int64_t min = static_cast(std::numeric_limits::min()); - constexpr int64_t max = static_cast(std::numeric_limits::max()); - if (n < min || max < n) { - throw runtime_error(str_t(trace) + "value exceeds type limits"); - } - return static_cast(n); - } - - template - std::pair resolution_to_minmax(int n, CodeFormat format) - { - const char* trace = "resolution_to_minmax : "; - check_code_width(trace, n); // for example, let n = 8 - int64_t min64 = -(static_cast(1) << (n - 1)); // min = -128 - int64_t max64 = -1 - min64; // max = +127 - if (CodeFormat::OffsetBinary == format) { - max64 -= min64; // max = 255 - min64 = 0; // min = 0 - } - T min = check_type_absolute_value(trace, min64); - T max = check_type_absolute_value(trace, max64); - return std::make_pair(min, max); - } - - str_t to_string(real_t n, FPFormat fmt = FPFormat::Auto, int max_prec = -1); +inline real_t bounded_db10(real_t msq_value) { + return 10 * + std::log10(std::clamp(msq_value, k_abs_min_msq, k_abs_max_msq)); +} + +inline real_t bounded_db20(real_t rms_value) { + return 20 * + std::log10(std::clamp(rms_value, k_abs_min_rms, k_abs_max_rms)); +} + +inline real_t bounded_db(const cplx_t &cplx_value) { + return bounded_db10(std::norm(cplx_value)); +} + +template +bool is_even(T n) { + return 0 == n % 2; +} + +template +bool is_odd(T n) { + return 1 == n % 2; +} + +template +bool is_pow2(T n) { + return (n < 1) ? false : (0 == (n & (n - 1))); +} + +template +int to_int(E e) { + static_assert(std::is_enum_v, "Requires enum type"); + return static_cast(e); +} + +template +void assert_eq(const char *trace, const char *name1, T val1, const char *name2, + T val2) { + if (val1 != val2) { + throw runtime_error(str_t(trace) + name1 + " != " + name2); + } +} + +template +void assert_gt0(const char *trace, const char *name, T val) { + if (!(static_cast(0) < val)) { + throw runtime_error(str_t(trace) + name + " <= 0"); + } +} + +template +void assert_ptr_not_null(const char *trace, const char *name, const T *p) { + if (nullptr == p) { + throw runtime_error(str_t(trace) + "pointer to " + name + + " is NULL"); + } +} + +template +void check_array(const char *trace, const char *name, const T *p, size_t size, + bool interleaved = false) { + assert_ptr_not_null(trace, name, p); + str_t n = str_t(name) + " size"; + assert_gt0(trace, n.c_str(), size); + if (interleaved && is_odd(size)) { + throw runtime_error(str_t(trace) + + " must be even if interleaved"); + } +} + +template +void check_array_pair(const char *trace, const char *name1, const T1 *p1, + size_t size1, const char *name2, const T2 *p2, + size_t size2, bool interleaved = false) { + check_array(trace, name1, p1, size1); + check_array(trace, name2, p2, size2); + str_t n1 = str_t(name1) + " size"; + str_t n2 = str_t(name2) + " size"; + assert_eq(trace, n1.c_str(), size1, n2.c_str(), size2); + if (interleaved && is_odd(size1)) { + throw runtime_error(str_t(trace) + + " must be even if interleaved"); + } +} + +inline void check_code_width(const char *trace, int n) { + if (n < k_abs_min_code_width || k_abs_max_code_width < n) { + throw runtime_error( + str_t(trace) + + "resolution outside absolute code width limits : [" + + std::to_string(k_abs_min_code_width) + ", " + + std::to_string(k_abs_max_code_width) + "]"); + } +} + +template +T check_type_absolute_value(const char *trace, int64_t n) { + static_assert(sizeof(T) <= sizeof(int64_t), "T is bigger than int64_t"); + static_assert(std::is_signed_v, "T must be signed"); + constexpr int64_t min = + static_cast(std::numeric_limits::min()); + constexpr int64_t max = + static_cast(std::numeric_limits::max()); + if (n < min || max < n) { + throw runtime_error(str_t(trace) + "value exceeds type limits"); + } + return static_cast(n); +} + +template +std::pair resolution_to_minmax(int n, CodeFormat format) { + const char *trace = "resolution_to_minmax : "; + check_code_width(trace, n); // for example, let n = 8 + int64_t min64 = -(static_cast(1) << (n - 1)); // min = -128 + int64_t max64 = -1 - min64; // max = +127 + if (CodeFormat::OffsetBinary == format) { + max64 -= min64; // max = 255 + min64 = 0; // min = 0 + } + T min = check_type_absolute_value(trace, min64); + T max = check_type_absolute_value(trace, max64); + return std::make_pair(min, max); +} + +str_t to_string(real_t n, FPFormat fmt = FPFormat::Auto, int max_prec = -1); } // namespace genalyzer_impl diff --git a/include/version.h b/include/version.h index 435b215..b0360ad 100644 --- a/include/version.h +++ b/include/version.h @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #define GENALYZER_VERSION_MAJOR 1 #define GENALYZER_VERSION_MINOR 0 #define GENALYZER_VERSION_PATCH 0 \ No newline at end of file diff --git a/include/version.hpp b/include/version.hpp index 1f2611c..617580b 100644 --- a/include/version.hpp +++ b/include/version.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_VERSION_HPP #define GENALYZER_IMPL_VERSION_HPP @@ -5,8 +8,8 @@ namespace genalyzer_impl { - std::string_view version_string(); - +std::string_view version_string(); + } // namespace genalyzer_impl #endif // GENALYZER_IMPL_VERSION_HPP \ No newline at end of file diff --git a/include/waveforms.hpp b/include/waveforms.hpp index 7e0787e..006fbe2 100644 --- a/include/waveforms.hpp +++ b/include/waveforms.hpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #ifndef GENALYZER_IMPL_WAVEFORMS_HPP #define GENALYZER_IMPL_WAVEFORMS_HPP @@ -6,37 +9,21 @@ #include namespace genalyzer_impl { - - void cos( - real_t* data, - size_t size, - real_t fs, - real_t ampl, - real_t freq, - real_t phase, - real_t td, - real_t tj - ); - - void gaussian(real_t* data, size_t size, real_t mean, real_t sd); - - void ramp(real_t* data, size_t size, real_t start, real_t stop, real_t noise); - - void sin( - real_t* data, - size_t size, - real_t fs, - real_t ampl, - real_t freq, - real_t phase, - real_t td, - real_t tj - ); - - template - std::map wf_analysis(const T* wf_data, size_t wf_size); - - const std::vector& wf_analysis_ordered_keys(); + +void cos(real_t *data, size_t size, real_t fs, real_t ampl, real_t freq, + real_t phase, real_t td, real_t tj); + +void gaussian(real_t *data, size_t size, real_t mean, real_t sd); + +void ramp(real_t *data, size_t size, real_t start, real_t stop, real_t noise); + +void sin(real_t *data, size_t size, real_t fs, real_t ampl, real_t freq, + real_t phase, real_t td, real_t tj); + +template +std::map wf_analysis(const T *wf_data, size_t wf_size); + +const std::vector &wf_analysis_ordered_keys(); } // namespace genalyzer_impl diff --git a/requirements_test.txt b/requirements_test.txt index dc7f412..f8046a5 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -7,4 +7,7 @@ numpy setuptools matplotlib tabulate -brokenaxes \ No newline at end of file +brokenaxes +pre-commit +cmakelint +clang-format \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7cdd5bc..8d05aab 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,5 @@ file(GLOB HEADER_LIST CONFIGURE_DEPENDS - "${PROJECT_SOURCE_DIR}/include/*.hpp") + "${PROJECT_SOURCE_DIR}/include/*.hpp") add_definitions(-DEXPORT_API) @@ -33,14 +33,14 @@ set_target_properties(genalyzer_plus_plus PROPERTIES VERSION ${CMAKE_PROJECT_VERSION} SOVERSION ${CMAKE_PROJECT_VERSION_MAJOR} FRAMEWORK TRUE - PUBLIC_HEADER "${HEADER_LIST}" - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED ON - CXX_EXTENSIONS OFF + PUBLIC_HEADER "${HEADER_LIST}" + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED ON + CXX_EXTENSIONS OFF ) set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" - CACHE PATH "Installation directory for libraries") + CACHE PATH "Installation directory for libraries") if(APPLE) find_package(PkgConfig) @@ -53,10 +53,10 @@ if(APPLE OR WIN32) endif() install(TARGETS genalyzer_plus_plus - ARCHIVE DESTINATION lib - LIBRARY DESTINATION "${INSTALL_LIB_DIR}" - RUNTIME DESTINATION bin - FRAMEWORK DESTINATION lib - PUBLIC_HEADER DESTINATION include) + ARCHIVE DESTINATION lib + LIBRARY DESTINATION "${INSTALL_LIB_DIR}" + RUNTIME DESTINATION bin + FRAMEWORK DESTINATION lib + PUBLIC_HEADER DESTINATION include) include(GNUInstallDirs) diff --git a/src/array_ops.cpp b/src/array_ops.cpp index 68c7891..346bd3c 100644 --- a/src/array_ops.cpp +++ b/src/array_ops.cpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #include "array_ops.hpp" #include "utils.hpp" @@ -7,65 +10,56 @@ namespace genalyzer_impl { - namespace { +namespace { - void c2r( - const real_t* in_data, - size_t in_size, - real_t* out_data, - size_t out_size, - real_t(*func)(const cplx_t&) - ) - { - assert_eq("", "input array size", in_size, "2 * output array size", 2 * out_size); - const cplx_t* cin_data = reinterpret_cast(in_data); - size_t cin_size = in_size / 2; - check_array_pair("", "input array", cin_data, cin_size, "output array", out_data, out_size); - std::transform(cin_data, cin_data + cin_size, out_data, func); - } +void c2r(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size, real_t (*func)(const cplx_t &)) { + assert_eq("", "input array size", in_size, "2 * output array size", + 2 * out_size); + const cplx_t *cin_data = reinterpret_cast(in_data); + size_t cin_size = in_size / 2; + check_array_pair("", "input array", cin_data, cin_size, "output array", + out_data, out_size); + std::transform(cin_data, cin_data + cin_size, out_data, func); +} - void r2r( - const real_t* in_data, - size_t in_size, - real_t* out_data, - size_t out_size, - real_t(*func)(real_t) - ) - { - check_array_pair("", "input array", in_data, in_size, "output array", out_data, out_size); - std::transform(in_data, in_data + in_size, out_data, func); - } +void r2r(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size, real_t (*func)(real_t)) { + check_array_pair("", "input array", in_data, in_size, "output array", + out_data, out_size); + std::transform(in_data, in_data + in_size, out_data, func); +} - } // namespace anonymous +} // namespace - void abs(const real_t* in_data, size_t in_size, real_t* out_data, size_t out_size) - { - c2r(in_data, in_size, out_data, out_size, std::abs); - } +void abs(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size) { + c2r(in_data, in_size, out_data, out_size, std::abs); +} - void angle(const real_t* in_data, size_t in_size, real_t* out_data, size_t out_size) - { - c2r(in_data, in_size, out_data, out_size, std::arg); - } +void angle(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size) { + c2r(in_data, in_size, out_data, out_size, std::arg); +} - void db(const real_t* in_data, size_t in_size, real_t* out_data, size_t out_size) - { - c2r(in_data, in_size, out_data, out_size, bounded_db); - } +void db(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size) { + c2r(in_data, in_size, out_data, out_size, bounded_db); +} - void db10(const real_t* in_data, size_t in_size, real_t* out_data, size_t out_size) - { - r2r(in_data, in_size, out_data, out_size, bounded_db10); - } +void db10(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size) { + r2r(in_data, in_size, out_data, out_size, bounded_db10); +} - void db20(const real_t* in_data, size_t in_size, real_t* out_data, size_t out_size) - { - r2r(in_data, in_size, out_data, out_size, bounded_db20); - } +void db20(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size) { + r2r(in_data, in_size, out_data, out_size, bounded_db20); +} - void norm(const real_t* in_data, size_t in_size, real_t* out_data, size_t out_size) - { - c2r(in_data, in_size, out_data, out_size, std::norm); - } +void norm(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size) { + c2r(in_data, in_size, out_data, out_size, std::norm); +} } // namespace genalyzer_impl \ No newline at end of file diff --git a/src/code_density.cpp b/src/code_density.cpp index 144e146..ad07cae 100644 --- a/src/code_density.cpp +++ b/src/code_density.cpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #include "code_density.hpp" #include "constants.hpp" @@ -11,434 +14,426 @@ #include namespace genalyzer_impl { - - namespace { - // Returns first and last non-zero indices - size_p first_and_last_nz(const uint64_t* data, size_t size) - { - size_t first = 0; - while (0 == data[first]) { - ++first; - if (first == size) { - return size_p(size, size); // no nz bins - } - } - size_t last = size - 1; - while (0 == data[last] && first < last) { - --last; - } - return size_p(first, last); - } +namespace { - void dnl_ramp(const uint64_t* hist_data, real_t* dnl_data, size_t size) - { - const size_p nz = first_and_last_nz(hist_data, size); - real_t sum = 0.0; - for (size_t i = nz.first + 1; i < nz.second; ++i) { // exclude first and last NZ bins - sum += static_cast(hist_data[i]); - } - if (0.0 == sum) { - std::fill(dnl_data, dnl_data + size, -1.0); - return; - } - const real_t avg_count = sum / (static_cast(nz.second - nz.first) - 1.0); - std::fill(dnl_data, dnl_data + nz.first + 1, -1.0); - for (size_t i = nz.first + 1; i < nz.second; ++i) { - dnl_data[i] = hist_data[i] / avg_count - 1.0; - } - std::fill(dnl_data + nz.second, dnl_data + size, -1.0); - } +// Returns first and last non-zero indices +size_p first_and_last_nz(const uint64_t *data, size_t size) { + size_t first = 0; + while (0 == data[first]) { + ++first; + if (first == size) { + return size_p(size, size); // no nz bins + } + } + size_t last = size - 1; + while (0 == data[last] && first < last) { + --last; + } + return size_p(first, last); +} - void dnl_tone(const uint64_t* hist_data, real_t* dnl_data, size_t size) - { - // 0. Check for minimum data - const size_p nz = first_and_last_nz(hist_data, size); - if (!(nz.first + 1 < nz.second)) { - std::fill(dnl_data, dnl_data + size, -1.0); - return; - } - // dnl_data stores the result of each of the following steps. - // 1a. Cumulative histogram - dnl_data[0] = static_cast(hist_data[0]); - for (size_t i = 1; i < size; ++i) { - dnl_data[i] = dnl_data[i - 1] + static_cast(hist_data[i]); - } - const real_t total_count = dnl_data[size - 1]; - // 1b. Find histogram peaks - size_t median_index = 0; - const real_t median_count = total_count * 0.5; - while (dnl_data[median_index] < median_count) { - ++median_index; - } - // find left peak in [nz.first, median_index] - size_t left_peak_index = nz.first; - uint64_t peak = hist_data[left_peak_index]; - for (size_t i = nz.first + 1; i <= median_index; ++i) { - if (peak < hist_data[i]) { // Note the less-than: if multiple bins contain the - peak = hist_data[i]; // peak count, get the leftmost - left_peak_index = i; - } - } - // find right peak in [median_index, nz.second] - size_t right_peak_index = median_index; - peak = hist_data[right_peak_index]; - for (size_t i = median_index; i <= nz.second; ++i) { - if (peak <= hist_data[i]) { // Note the less-than-or-equal: if multiple bins - peak = hist_data[i]; // contain the same peak count, get the rightmost - right_peak_index = i; - } - } - // Ensure plausible results: - if (!(left_peak_index < median_index && median_index < right_peak_index)) { - std::fill(dnl_data, dnl_data + size, -1.0); - throw runtime_error("dnl : unable to locate histogram peaks"); - } - // 2. Code transition points - const real_t k1 = k_pi / total_count; - for (size_t i = 0; i < size; ++i) { - dnl_data[i] = -std::cos(k1 * dnl_data[i]); - } - // 3. Code widths - size_t left_dnl_index = left_peak_index; - if (nz.first == left_dnl_index) { // exclude first NZ bin - left_dnl_index += 1; // certain: 0 < left_dnl_index <= median_index - } - size_t right_dnl_index = right_peak_index; - if (nz.second == right_dnl_index) { // exclude last NZ bin - right_dnl_index -= 1; // certain: median_index <= right_peak_index < size - 1 - } - real_t code_width_sum = 0.0; - // width of code n is the difference between transition points of n and n-1 - for (size_t i = right_dnl_index; left_dnl_index <= i; --i) { - dnl_data[i] -= dnl_data[i - 1]; - code_width_sum += dnl_data[i]; - } - size_t num_dnl_codes = (right_dnl_index - left_dnl_index) + 1; - const real_t avg_code_width = code_width_sum / static_cast(num_dnl_codes); - if (avg_code_width <= 0.0) { // not sure how this can happen, but just in case... - throw runtime_error("dnl : avg_code_width <= 0.0"); - } - std::fill(dnl_data, dnl_data + left_dnl_index, 0.0); - std::fill(dnl_data + right_dnl_index + 1, dnl_data + size, 0.0); - // 4. DNL - const real_t k2 = 1 / avg_code_width; - for (size_t i = 0; i < size; ++i) { - dnl_data[i] = std::fma(k2, dnl_data[i], -1.0); - } - } +void dnl_ramp(const uint64_t *hist_data, real_t *dnl_data, size_t size) { + const size_p nz = first_and_last_nz(hist_data, size); + real_t sum = 0.0; + for (size_t i = nz.first + 1; i < nz.second; + ++i) { // exclude first and last NZ bins + sum += static_cast(hist_data[i]); + } + if (0.0 == sum) { + std::fill(dnl_data, dnl_data + size, -1.0); + return; + } + const real_t avg_count = + sum / (static_cast(nz.second - nz.first) - 1.0); + std::fill(dnl_data, dnl_data + nz.first + 1, -1.0); + for (size_t i = nz.first + 1; i < nz.second; ++i) { + dnl_data[i] = hist_data[i] / avg_count - 1.0; + } + std::fill(dnl_data + nz.second, dnl_data + size, -1.0); +} - } // namespace anonymous +void dnl_tone(const uint64_t *hist_data, real_t *dnl_data, size_t size) { + // 0. Check for minimum data + const size_p nz = first_and_last_nz(hist_data, size); + if (!(nz.first + 1 < nz.second)) { + std::fill(dnl_data, dnl_data + size, -1.0); + return; + } + // dnl_data stores the result of each of the following steps. + // 1a. Cumulative histogram + dnl_data[0] = static_cast(hist_data[0]); + for (size_t i = 1; i < size; ++i) { + dnl_data[i] = + dnl_data[i - 1] + static_cast(hist_data[i]); + } + const real_t total_count = dnl_data[size - 1]; + // 1b. Find histogram peaks + size_t median_index = 0; + const real_t median_count = total_count * 0.5; + while (dnl_data[median_index] < median_count) { + ++median_index; + } + // find left peak in [nz.first, median_index] + size_t left_peak_index = nz.first; + uint64_t peak = hist_data[left_peak_index]; + for (size_t i = nz.first + 1; i <= median_index; ++i) { + if (peak < + hist_data[i]) { // Note the less-than: if multiple bins contain the + peak = hist_data[i]; // peak count, get the leftmost + left_peak_index = i; + } + } + // find right peak in [median_index, nz.second] + size_t right_peak_index = median_index; + peak = hist_data[right_peak_index]; + for (size_t i = median_index; i <= nz.second; ++i) { + if (peak <= + hist_data[i]) { // Note the less-than-or-equal: if multiple bins + peak = hist_data + [i]; // contain the same peak count, get the rightmost + right_peak_index = i; + } + } + // Ensure plausible results: + if (!(left_peak_index < median_index && + median_index < right_peak_index)) { + std::fill(dnl_data, dnl_data + size, -1.0); + throw runtime_error("dnl : unable to locate histogram peaks"); + } + // 2. Code transition points + const real_t k1 = k_pi / total_count; + for (size_t i = 0; i < size; ++i) { + dnl_data[i] = -std::cos(k1 * dnl_data[i]); + } + // 3. Code widths + size_t left_dnl_index = left_peak_index; + if (nz.first == left_dnl_index) { // exclude first NZ bin + left_dnl_index += + 1; // certain: 0 < left_dnl_index <= median_index + } + size_t right_dnl_index = right_peak_index; + if (nz.second == right_dnl_index) { // exclude last NZ bin + right_dnl_index -= + 1; // certain: median_index <= right_peak_index < size - 1 + } + real_t code_width_sum = 0.0; + // width of code n is the difference between transition points of n and n-1 + for (size_t i = right_dnl_index; left_dnl_index <= i; --i) { + dnl_data[i] -= dnl_data[i - 1]; + code_width_sum += dnl_data[i]; + } + size_t num_dnl_codes = (right_dnl_index - left_dnl_index) + 1; + const real_t avg_code_width = + code_width_sum / static_cast(num_dnl_codes); + if (avg_code_width <= + 0.0) { // not sure how this can happen, but just in case... + throw runtime_error("dnl : avg_code_width <= 0.0"); + } + std::fill(dnl_data, dnl_data + left_dnl_index, 0.0); + std::fill(dnl_data + right_dnl_index + 1, dnl_data + size, 0.0); + // 4. DNL + const real_t k2 = 1 / avg_code_width; + for (size_t i = 0; i < size; ++i) { + dnl_data[i] = std::fma(k2, dnl_data[i], -1.0); + } +} - size_t code_density_size(int n, CodeFormat format) - { - std::pair mm = resolution_to_minmax(n, format); - return code_densityx_size(mm.first, mm.second); - } +} // namespace - size_t code_densityx_size(int64_t min, int64_t max) - { - str_t trace = "code_densityx_size : "; - if (max < min) { - throw runtime_error(trace + "max < min"); - } - const int64_t abs_max_range = static_cast(1) << k_abs_max_code_width; - const int64_t abs_min = -(abs_max_range >> 1); - const int64_t abs_max = abs_max_range - 1; - if (min < abs_min) { - throw runtime_error(trace + "min < absolute min"); - } - if (abs_max < max) { - throw runtime_error(trace + "absolute max < max"); - } - // now it is safe to calculate range - const int64_t range = (max - min) + 1; - if (abs_max_range < range) { - throw runtime_error(trace + "range exceeds absolute max"); - } - return static_cast(range); - } +size_t code_density_size(int n, CodeFormat format) { + std::pair mm = + resolution_to_minmax(n, format); + return code_densityx_size(mm.first, mm.second); +} - void code_axis(real_t* data, size_t size, int n, CodeFormat format) - { - std::pair mm = resolution_to_minmax(n, format); - code_axisx(data, size, mm.first, mm.second); - } +size_t code_densityx_size(int64_t min, int64_t max) { + str_t trace = "code_densityx_size : "; + if (max < min) { + throw runtime_error(trace + "max < min"); + } + const int64_t abs_max_range = static_cast(1) + << k_abs_max_code_width; + const int64_t abs_min = -(abs_max_range >> 1); + const int64_t abs_max = abs_max_range - 1; + if (min < abs_min) { + throw runtime_error(trace + "min < absolute min"); + } + if (abs_max < max) { + throw runtime_error(trace + "absolute max < max"); + } + // now it is safe to calculate range + const int64_t range = (max - min) + 1; + if (abs_max_range < range) { + throw runtime_error(trace + "range exceeds absolute max"); + } + return static_cast(range); +} - void code_axisx(real_t* data, size_t size, int64_t min, int64_t max) - { - const char* trace = "code_axisx : "; - check_array(trace, "array", data, size); - size_t size_expected = code_densityx_size(min, max); - assert_eq(trace, "array size", size, "expected", size_expected); - real_t x = static_cast(min); - for (size_t i = 0; i < size; ++i) { - data[i] = x; - x += 1.0; - } - } +void code_axis(real_t *data, size_t size, int n, CodeFormat format) { + std::pair mm = + resolution_to_minmax(n, format); + code_axisx(data, size, mm.first, mm.second); +} - void dnl( - real_t* dnl_data, - size_t dnl_size, - const uint64_t* hist_data, - size_t hist_size, - DnlSignal type - ) - { - check_array_pair("dnl : ", "hist array", hist_data, hist_size, "dnl array", dnl_data, dnl_size); - switch (type) - { - case DnlSignal::Ramp: - dnl_ramp(hist_data, dnl_data, dnl_size); - return; - case DnlSignal::Tone: - dnl_tone(hist_data, dnl_data, dnl_size); - return; - default: - throw runtime_error("dnl : DNL not implemented for signal type"); - } - } +void code_axisx(real_t *data, size_t size, int64_t min, int64_t max) { + const char *trace = "code_axisx : "; + check_array(trace, "array", data, size); + size_t size_expected = code_densityx_size(min, max); + assert_eq(trace, "array size", size, "expected", size_expected); + real_t x = static_cast(min); + for (size_t i = 0; i < size; ++i) { + data[i] = x; + x += 1.0; + } +} - std::map dnl_analysis(const real_t* data, size_t size) - { - check_array("", "dnl array", data, size); - // First and last non-missing codes - size_t first_nm_index = 0; - while (first_nm_index < size) { - if (-1.0 < data[first_nm_index++]) { - break; - } - } - size_t last_nm_index = size - 1; - real_t num_codes = 0.0; - if (first_nm_index < size) { // if there are any non-missing codes - while (first_nm_index < last_nm_index) { - if (-1.0 < data[last_nm_index--]) { - break; - } - } - num_codes = 1.0 + static_cast(last_nm_index - first_nm_index); - } else { - last_nm_index = first_nm_index; - } - // Results - std_reduce_t r (size); - real_t avg = 0.0; - real_t rms = 0.0; - if (0.0 < num_codes) { - r = std_reduce(data, size, first_nm_index, last_nm_index + 1); - avg = r.sum / num_codes; - rms = std::sqrt(r.sumsq / num_codes); - } else { - r.min = -1.0; - r.max = -1.0; - avg = -1.0; - rms = 1.0; - } - std::vector keys = dnl_analysis_ordered_keys(); - return std::map { - { keys[0] , r.min }, - { keys[1] , r.max }, - { keys[2] , avg }, - { keys[3] , rms }, - { keys[4] , static_cast(r.min_index) }, - { keys[5] , static_cast(r.max_index) }, - { keys[6] , static_cast(first_nm_index) }, - { keys[7] , static_cast(last_nm_index) }, - { keys[8] , num_codes }}; - } +void dnl(real_t *dnl_data, size_t dnl_size, const uint64_t *hist_data, + size_t hist_size, DnlSignal type) { + check_array_pair("dnl : ", "hist array", hist_data, hist_size, + "dnl array", dnl_data, dnl_size); + switch (type) { + case DnlSignal::Ramp: + dnl_ramp(hist_data, dnl_data, dnl_size); + return; + case DnlSignal::Tone: + dnl_tone(hist_data, dnl_data, dnl_size); + return; + default: + throw runtime_error( + "dnl : DNL not implemented for signal type"); + } +} - const std::vector& dnl_analysis_ordered_keys() - { - // first_nm_index, last_nm_index - static const std::vector keys { - "min", // min DNL value - "max", // max DNL value - "avg", // average DNL value - "rms", // RMS DNL value - "min_index", // index of min DNL value - "max_index", // index of max DNL value - "first_nm_index", // index of first non-missing code - "last_nm_index", // index of last non-missing code - "nm_range" // non-missing code range - }; - return keys; - } +std::map dnl_analysis(const real_t *data, size_t size) { + check_array("", "dnl array", data, size); + // First and last non-missing codes + size_t first_nm_index = 0; + while (first_nm_index < size) { + if (-1.0 < data[first_nm_index++]) { + break; + } + } + size_t last_nm_index = size - 1; + real_t num_codes = 0.0; + if (first_nm_index < size) { // if there are any non-missing codes + while (first_nm_index < last_nm_index) { + if (-1.0 < data[last_nm_index--]) { + break; + } + } + num_codes = 1.0 + + static_cast(last_nm_index - first_nm_index); + } else { + last_nm_index = first_nm_index; + } + // Results + std_reduce_t r(size); + real_t avg = 0.0; + real_t rms = 0.0; + if (0.0 < num_codes) { + r = std_reduce(data, size, first_nm_index, last_nm_index + 1); + avg = r.sum / num_codes; + rms = std::sqrt(r.sumsq / num_codes); + } else { + r.min = -1.0; + r.max = -1.0; + avg = -1.0; + rms = 1.0; + } + std::vector keys = dnl_analysis_ordered_keys(); + return std::map{ + { keys[0], r.min }, + { keys[1], r.max }, + { keys[2], avg }, + { keys[3], rms }, + { keys[4], static_cast(r.min_index) }, + { keys[5], static_cast(r.max_index) }, + { keys[6], static_cast(first_nm_index) }, + { keys[7], static_cast(last_nm_index) }, + { keys[8], num_codes } + }; +} - template - void hist( - uint64_t* hist_data, - size_t hist_size, - const T* wf_data, - size_t wf_size, - int n, - CodeFormat format, - bool preserve - ) - { - std::pair mm = resolution_to_minmax(n, format); - histx(hist_data, hist_size, wf_data, wf_size, mm.first, mm.second, preserve); - } +const std::vector &dnl_analysis_ordered_keys() { + // first_nm_index, last_nm_index + static const std::vector keys{ + "min", // min DNL value + "max", // max DNL value + "avg", // average DNL value + "rms", // RMS DNL value + "min_index", // index of min DNL value + "max_index", // index of max DNL value + "first_nm_index", // index of first non-missing code + "last_nm_index", // index of last non-missing code + "nm_range" // non-missing code range + }; + return keys; +} - template void hist(uint64_t*, size_t, const int16_t*, size_t, int, CodeFormat, bool); - template void hist(uint64_t*, size_t, const int32_t*, size_t, int, CodeFormat, bool); - template void hist(uint64_t*, size_t, const int64_t*, size_t, int, CodeFormat, bool); +template +void hist(uint64_t *hist_data, size_t hist_size, const T *wf_data, + size_t wf_size, int n, CodeFormat format, bool preserve) { + std::pair mm = + resolution_to_minmax(n, format); + histx(hist_data, hist_size, wf_data, wf_size, mm.first, mm.second, + preserve); +} - template - void histx( - uint64_t* hist_data, - size_t hist_size, - const T* wf_data, - size_t wf_size, - int64_t min, - int64_t max, - bool preserve - ) - { - check_array("histx : ", "hist array", hist_data, hist_size); - check_array("histx : ", "waveform array", wf_data, wf_size); - size_t size_expected = code_densityx_size(min, max); - assert_eq("histx : ", "hist array size", hist_size, "expected", size_expected); - if (!preserve) { - std::fill(hist_data, hist_data + hist_size, 0); - } - for (size_t i = 0; i < wf_size; ++i) { - if (min <= wf_data[i] && wf_data[i] <= max) { - ++hist_data[wf_data[i] - min]; - } - } - } +template void hist(uint64_t *, size_t, const int16_t *, size_t, int, CodeFormat, + bool); +template void hist(uint64_t *, size_t, const int32_t *, size_t, int, CodeFormat, + bool); +template void hist(uint64_t *, size_t, const int64_t *, size_t, int, CodeFormat, + bool); - template void histx(uint64_t*, size_t, const int16_t*, size_t, int64_t, int64_t, bool); - template void histx(uint64_t*, size_t, const int32_t*, size_t, int64_t, int64_t, bool); - template void histx(uint64_t*, size_t, const int64_t*, size_t, int64_t, int64_t, bool); +template +void histx(uint64_t *hist_data, size_t hist_size, const T *wf_data, + size_t wf_size, int64_t min, int64_t max, bool preserve) { + check_array("histx : ", "hist array", hist_data, hist_size); + check_array("histx : ", "waveform array", wf_data, wf_size); + size_t size_expected = code_densityx_size(min, max); + assert_eq("histx : ", "hist array size", hist_size, "expected", + size_expected); + if (!preserve) { + std::fill(hist_data, hist_data + hist_size, 0); + } + for (size_t i = 0; i < wf_size; ++i) { + if (min <= wf_data[i] && wf_data[i] <= max) { + ++hist_data[wf_data[i] - min]; + } + } +} - std::map hist_analysis(const uint64_t* data, size_t size) - { - check_array("", "hist array", data, size); - // Cummulative Histogram - std::vector chist (size); - chist[0] = static_cast(data[0]); - for (size_t i = 1; i < size; ++i) { - chist[i] = chist[i - 1] + static_cast(data[i]); - } - // First and last non-zero indexes - size_t first_nz_index = 0; - while (first_nz_index < size) { - if (0 < data[first_nz_index++]) { - break; - } - } - size_t last_nz_index = size - 1; - real_t num_bins = 0.0; - if (first_nz_index < size) { // if there are any non-zero bins - while (first_nz_index < last_nz_index) { - if (0 < data[last_nz_index--]) { - break; - } - } - num_bins = 1.0 + static_cast(last_nz_index - first_nz_index); - } else { - last_nz_index = first_nz_index; - } - // Results - std::vector keys = hist_analysis_ordered_keys(); - return std::map { - { keys[0] , chist.back() }, - { keys[1] , static_cast(first_nz_index) }, - { keys[2] , static_cast(last_nz_index) }, - { keys[3] , num_bins }}; - } +template void histx(uint64_t *, size_t, const int16_t *, size_t, int64_t, + int64_t, bool); +template void histx(uint64_t *, size_t, const int32_t *, size_t, int64_t, + int64_t, bool); +template void histx(uint64_t *, size_t, const int64_t *, size_t, int64_t, + int64_t, bool); - const std::vector& hist_analysis_ordered_keys() - { - static const std::vector keys { - "sum", // total histogram hits - "first_nz_index", // index of first non-zero bin - "last_nz_index", // index of last non-zero bin - "nz_range" // non-zero bin range - }; - return keys; - } +std::map hist_analysis(const uint64_t *data, size_t size) { + check_array("", "hist array", data, size); + // Cummulative Histogram + std::vector chist(size); + chist[0] = static_cast(data[0]); + for (size_t i = 1; i < size; ++i) { + chist[i] = chist[i - 1] + static_cast(data[i]); + } + // First and last non-zero indexes + size_t first_nz_index = 0; + while (first_nz_index < size) { + if (0 < data[first_nz_index++]) { + break; + } + } + size_t last_nz_index = size - 1; + real_t num_bins = 0.0; + if (first_nz_index < size) { // if there are any non-zero bins + while (first_nz_index < last_nz_index) { + if (0 < data[last_nz_index--]) { + break; + } + } + num_bins = 1.0 + + static_cast(last_nz_index - first_nz_index); + } else { + last_nz_index = first_nz_index; + } + // Results + std::vector keys = hist_analysis_ordered_keys(); + return std::map{ + { keys[0], chist.back() }, + { keys[1], static_cast(first_nz_index) }, + { keys[2], static_cast(last_nz_index) }, + { keys[3], num_bins } + }; +} - void inl( - real_t* inl_data, - size_t inl_size, - const real_t* dnl_data, - size_t dnl_size, - InlLineFit fit - ) - { - check_array_pair("inl : ", "dnl array", dnl_data, dnl_size, "inl array", inl_data, inl_size); - size_t first = 0; - while (dnl_data[first] <= -1.0) { - inl_data[first++] = 0.0; - if (first == dnl_size) { - return; // all missing codes - } - } - size_t last = dnl_size - 1; - while (dnl_data[last] <= -1.0 && first < last) { - inl_data[last--] = 0.0; - } - std::partial_sum(dnl_data + first, dnl_data + last + 1, inl_data + first); - real_t m = 0.0; - real_t b = 0.0; - switch (fit) - { - case InlLineFit::NoFit: - return; - case InlLineFit::BestFit: { - // https://en.wikipedia.org/wiki/Ordinary_least_squares - real_t n = static_cast(last - first) + 1.0; - real_t sx = 0.0; - real_t sy = 0.0; - real_t sxx = 0.0; - real_t sxy = 0.0; - for (size_t i = first; i <= last; ++i) { - real_t x = static_cast(i); - sx += x; - sy += inl_data[i]; - sxx += x * x; - sxy += x * inl_data[i]; - } - m = (n * sxy - sx * sy) / (n * sxx - sx * sx); - b = (sy - m * sx) / n; - break; - } case InlLineFit::EndFit: { - m = (inl_data[last] - inl_data[first]) / static_cast(last - first); - b = inl_data[first] - m * static_cast(first); - break; - } default: - throw runtime_error("inl : line fit not implemented"); - } - for (size_t i = first; i <= last; ++i) { - inl_data[i] -= m * static_cast(i) + b; - } - } +const std::vector &hist_analysis_ordered_keys() { + static const std::vector keys{ + "sum", // total histogram hits + "first_nz_index", // index of first non-zero bin + "last_nz_index", // index of last non-zero bin + "nz_range" // non-zero bin range + }; + return keys; +} - std::map inl_analysis(const real_t* data, size_t size) - { - check_array("", "inl array", data, size); - std_reduce_t r = std_reduce(data, size, 0, size); - std::vector keys = inl_analysis_ordered_keys(); - return std::map { - { keys[0] , r.min }, - { keys[1] , r.max }, - { keys[2] , static_cast(r.min_index) }, - { keys[3] , static_cast(r.max_index) }}; - } +void inl(real_t *inl_data, size_t inl_size, const real_t *dnl_data, + size_t dnl_size, InlLineFit fit) { + check_array_pair("inl : ", "dnl array", dnl_data, dnl_size, "inl array", + inl_data, inl_size); + size_t first = 0; + while (dnl_data[first] <= -1.0) { + inl_data[first++] = 0.0; + if (first == dnl_size) { + return; // all missing codes + } + } + size_t last = dnl_size - 1; + while (dnl_data[last] <= -1.0 && first < last) { + inl_data[last--] = 0.0; + } + std::partial_sum(dnl_data + first, dnl_data + last + 1, + inl_data + first); + real_t m = 0.0; + real_t b = 0.0; + switch (fit) { + case InlLineFit::NoFit: + return; + case InlLineFit::BestFit: { + // https://en.wikipedia.org/wiki/Ordinary_least_squares + real_t n = static_cast(last - first) + 1.0; + real_t sx = 0.0; + real_t sy = 0.0; + real_t sxx = 0.0; + real_t sxy = 0.0; + for (size_t i = first; i <= last; ++i) { + real_t x = static_cast(i); + sx += x; + sy += inl_data[i]; + sxx += x * x; + sxy += x * inl_data[i]; + } + m = (n * sxy - sx * sy) / (n * sxx - sx * sx); + b = (sy - m * sx) / n; + break; + } + case InlLineFit::EndFit: { + m = (inl_data[last] - inl_data[first]) / + static_cast(last - first); + b = inl_data[first] - m * static_cast(first); + break; + } + default: + throw runtime_error("inl : line fit not implemented"); + } + for (size_t i = first; i <= last; ++i) { + inl_data[i] -= m * static_cast(i) + b; + } +} - const std::vector& inl_analysis_ordered_keys() - { - static const std::vector keys { - "min", // min INL value - "max", // max INL value - "min_index", // index of min INL value - "max_index" // index of max INL value - }; - return keys; - } +std::map inl_analysis(const real_t *data, size_t size) { + check_array("", "inl array", data, size); + std_reduce_t r = std_reduce(data, size, 0, size); + std::vector keys = inl_analysis_ordered_keys(); + return std::map{ + { keys[0], r.min }, + { keys[1], r.max }, + { keys[2], static_cast(r.min_index) }, + { keys[3], static_cast(r.max_index) } + }; +} + +const std::vector &inl_analysis_ordered_keys() { + static const std::vector keys{ + "min", // min INL value + "max", // max INL value + "min_index", // index of min INL value + "max_index" // index of max INL value + }; + return keys; +} } // namespace genalyzer_impl \ No newline at end of file diff --git a/src/enum_map.cpp b/src/enum_map.cpp index dee6cb8..c68cd18 100644 --- a/src/enum_map.cpp +++ b/src/enum_map.cpp @@ -1,49 +1,54 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #include "enum_map.hpp" namespace genalyzer_impl { - enum_map::enum_map(const char* name, std::initializer_list> list) - : m_name (name), - m_itos {}, - m_stoi {} - { - if (m_name.empty()) { - throw runtime_error("enum_map : enumeration name is required"); - } - for (const auto& es : list) { - int i = es.first; - const str_t& s = es.second; - if (s.empty()) { - throw runtime_error("enum_map : enumerator name is required"); - } - bool success = false; - std::tie(std::ignore, success) = m_itos.emplace(i, s); - if (!success) { - throw runtime_error("enum_map : enumerator already exists"); - } - std::tie(std::ignore, success) = m_stoi.emplace(s, i); - if (!success) { - throw runtime_error("enum_map : enumerator name already exists"); - } - } - } +enum_map::enum_map(const char *name, + std::initializer_list> list) : + m_name(name), m_itos{}, m_stoi{} { + if (m_name.empty()) { + throw runtime_error("enum_map : enumeration name is required"); + } + for (const auto &es : list) { + int i = es.first; + const str_t &s = es.second; + if (s.empty()) { + throw runtime_error( + "enum_map : enumerator name is required"); + } + bool success = false; + std::tie(std::ignore, success) = m_itos.emplace(i, s); + if (!success) { + throw runtime_error( + "enum_map : enumerator already exists"); + } + std::tie(std::ignore, success) = m_stoi.emplace(s, i); + if (!success) { + throw runtime_error( + "enum_map : enumerator name already exists"); + } + } +} - bool enum_map::contains(int i, bool throw_if_not_found) const - { - bool not_found = m_itos.end() == m_itos.find(i); - if (not_found && throw_if_not_found) { - throw runtime_error("enum_map : " + m_name + " does not contain value " + std::to_string(i)); - } - return !not_found; - } +bool enum_map::contains(int i, bool throw_if_not_found) const { + bool not_found = m_itos.end() == m_itos.find(i); + if (not_found && throw_if_not_found) { + throw runtime_error("enum_map : " + m_name + + " does not contain value " + + std::to_string(i)); + } + return !not_found; +} - bool enum_map::contains(const str_t& s, bool throw_if_not_found) const - { - bool not_found = m_stoi.end() == m_stoi.find(s); - if (not_found && throw_if_not_found) { - throw runtime_error("enum_map : " + m_name + " : does not contain enumerator " + s); - } - return !not_found; - } +bool enum_map::contains(const str_t &s, bool throw_if_not_found) const { + bool not_found = m_stoi.end() == m_stoi.find(s); + if (not_found && throw_if_not_found) { + throw runtime_error("enum_map : " + m_name + + " : does not contain enumerator " + s); + } + return !not_found; +} } // namespace genalyzer_impl \ No newline at end of file diff --git a/src/enum_maps.cpp b/src/enum_maps.cpp index 0d88893..a2fb193 100644 --- a/src/enum_maps.cpp +++ b/src/enum_maps.cpp @@ -1,100 +1,93 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #include "enum_maps.hpp" #include namespace genalyzer_impl { - const std::map> enumeration_map = { - { analysis_type_map.name() , std::cref(analysis_type_map) }, - { code_format_map.name() , std::cref(code_format_map) }, - { dnl_signal_map.name() , std::cref(dnl_signal_map) }, - { fa_comp_tag_map.name() , std::cref(fa_comp_tag_map) }, - { fa_ssb_map.name() , std::cref(fa_ssb_map) }, - { freq_axis_format_map.name() , std::cref(freq_axis_format_map) }, - { freq_axis_type_map.name() , std::cref(freq_axis_type_map) }, - { inl_line_fit_map.name() , std::cref(inl_line_fit_map) }, - { rfft_scale_map.name() , std::cref(rfft_scale_map) }, - { window_map.name() , std::cref(window_map) } - }; +const std::map> enumeration_map = { + { analysis_type_map.name(), std::cref(analysis_type_map) }, + { code_format_map.name(), std::cref(code_format_map) }, + { dnl_signal_map.name(), std::cref(dnl_signal_map) }, + { fa_comp_tag_map.name(), std::cref(fa_comp_tag_map) }, + { fa_ssb_map.name(), std::cref(fa_ssb_map) }, + { freq_axis_format_map.name(), std::cref(freq_axis_format_map) }, + { freq_axis_type_map.name(), std::cref(freq_axis_type_map) }, + { inl_line_fit_map.name(), std::cref(inl_line_fit_map) }, + { rfft_scale_map.name(), std::cref(rfft_scale_map) }, + { window_map.name(), std::cref(window_map) } +}; - int enum_value(const str_t& enumeration, const str_t& enumerator) - { - if (enumeration_map.find(enumeration) == enumeration_map.end()) { - throw runtime_error("enum_value : unknown enumeration, '" + enumeration + "'"); - } - const enum_map& em = enumeration_map.at(enumeration); - em.contains(enumerator, true); - return em.at(enumerator); - } +int enum_value(const str_t &enumeration, const str_t &enumerator) { + if (enumeration_map.find(enumeration) == enumeration_map.end()) { + throw runtime_error("enum_value : unknown enumeration, '" + + enumeration + "'"); + } + const enum_map &em = enumeration_map.at(enumeration); + em.contains(enumerator, true); + return em.at(enumerator); +} - template<> - AnalysisType get_enum(int i) - { - analysis_type_map.contains(i, true); - return static_cast(i); - } +template <> +AnalysisType get_enum(int i) { + analysis_type_map.contains(i, true); + return static_cast(i); +} - template<> - CodeFormat get_enum(int i) - { - code_format_map.contains(i, true); - return static_cast(i); - } +template <> +CodeFormat get_enum(int i) { + code_format_map.contains(i, true); + return static_cast(i); +} - template<> - DnlSignal get_enum(int i) - { - dnl_signal_map.contains(i, true); - return static_cast(i); - } +template <> +DnlSignal get_enum(int i) { + dnl_signal_map.contains(i, true); + return static_cast(i); +} - template<> - FACompTag get_enum(int i) - { - fa_comp_tag_map.contains(i, true); - return static_cast(i); - } +template <> +FACompTag get_enum(int i) { + fa_comp_tag_map.contains(i, true); + return static_cast(i); +} - template<> - FASsb get_enum(int i) - { - fa_ssb_map.contains(i, true); - return static_cast(i); - } +template <> +FASsb get_enum(int i) { + fa_ssb_map.contains(i, true); + return static_cast(i); +} - template<> - FreqAxisFormat get_enum(int i) - { - freq_axis_format_map.contains(i, true); - return static_cast(i); - } +template <> +FreqAxisFormat get_enum(int i) { + freq_axis_format_map.contains(i, true); + return static_cast(i); +} - template<> - FreqAxisType get_enum(int i) - { - freq_axis_type_map.contains(i, true); - return static_cast(i); - } +template <> +FreqAxisType get_enum(int i) { + freq_axis_type_map.contains(i, true); + return static_cast(i); +} - template<> - InlLineFit get_enum(int i) - { - inl_line_fit_map.contains(i, true); - return static_cast(i); - } +template <> +InlLineFit get_enum(int i) { + inl_line_fit_map.contains(i, true); + return static_cast(i); +} - template<> - RfftScale get_enum(int i) - { - rfft_scale_map.contains(i, true); - return static_cast(i); - } +template <> +RfftScale get_enum(int i) { + rfft_scale_map.contains(i, true); + return static_cast(i); +} - template<> - Window get_enum(int i) - { - window_map.contains(i, true); - return static_cast(i); - } +template <> +Window get_enum(int i) { + window_map.contains(i, true); + return static_cast(i); +} } // namespace genalyzer_impl \ No newline at end of file diff --git a/src/expression.cpp b/src/expression.cpp index 13251b9..6d0effe 100644 --- a/src/expression.cpp +++ b/src/expression.cpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #include "expression.hpp" #include "exceptions.hpp" @@ -11,669 +14,718 @@ namespace genalyzer_impl { // expression tokens - enum class TokenType { - Number, Operator, Parenthesis, Variable - }; - - enum class OpType { - Add, Sub, Mul, Div, Mod, UPlus, UMinus, Exp - }; - - enum class OpArity { - Unary, Binary - }; - - enum class OpAssoc { - Left, Right - }; - - enum OpProps { - OpPropsSymbol = 0, - OpPropsPrec, - OpPropsArity, - OpPropsAssoc - }; - - enum class ParenType { - Left, Right - }; - - struct expression_token - { - using pointer = std::unique_ptr; - - virtual ~expression_token() = default; - - virtual pointer clone() const = 0; - - virtual TokenType type() const = 0; - }; - - struct num_token final : public expression_token - { - num_token(real_t n) - : num {n} - {} - - pointer clone() const override - { - return std::make_unique(*this); - } - - TokenType type() const override - { - return TokenType::Number; - } - - real_t num; - }; - - struct op_token final : public expression_token - { - op_token(OpType o) - : op {o} - { - std::tuple props; - switch (op) - { - case OpType::Add : props = std::make_tuple('+', 0, OpArity::Binary, OpAssoc::Left ); break; - case OpType::Sub : props = std::make_tuple('-', 0, OpArity::Binary, OpAssoc::Left ); break; - case OpType::Mul : props = std::make_tuple('*', 1, OpArity::Binary, OpAssoc::Left ); break; - case OpType::Div : props = std::make_tuple('/', 1, OpArity::Binary, OpAssoc::Left ); break; - case OpType::Mod : props = std::make_tuple('%', 1, OpArity::Binary, OpAssoc::Left ); break; - case OpType::UPlus : props = std::make_tuple('+', 2, OpArity::Unary, OpAssoc::Right); break; - case OpType::UMinus : props = std::make_tuple('-', 2, OpArity::Unary, OpAssoc::Right); break; - case OpType::Exp : props = std::make_tuple('^', 2, OpArity::Binary, OpAssoc::Right); break; - } - symbol = std::get<0>(props); - prec = std::get<1>(props); - arity = std::get<2>(props); - assoc = std::get<3>(props); - } - - pointer clone() const override - { - return std::make_unique(*this); - } - - TokenType type() const override - { - return TokenType::Operator; - } - - bool operator<(const op_token& that) const - { - return this->prec < that.prec; - } - - bool operator<=(const op_token& that) const - { - return this->prec <= that.prec; - } - - OpType op; - char symbol; - int prec; - OpArity arity; - OpAssoc assoc; - }; - - struct paren_token final : public expression_token - { - paren_token(ParenType p) - : paren {p}, - pchar {ParenType::Left == paren ? '(' : ')'} - {} - - pointer clone() const override - { - return std::make_unique(*this); - } - - TokenType type() const override - { - return TokenType::Parenthesis; - } - - ParenType paren; - char pchar; - }; - - struct var_token final : public expression_token - { - - var_token(const str_t& v) - : var {v} - {} - - pointer clone() const override - { - return std::make_unique(*this); - } - - TokenType type() const override - { - return TokenType::Variable; - } - - str_t var; - }; - -} // genalyzer_impl +enum class TokenType { Number, + Operator, + Parenthesis, + Variable }; + +enum class OpType { Add, + Sub, + Mul, + Div, + Mod, + UPlus, + UMinus, + Exp }; + +enum class OpArity { Unary, + Binary }; + +enum class OpAssoc { Left, + Right }; + +enum OpProps { OpPropsSymbol = 0, + OpPropsPrec, + OpPropsArity, + OpPropsAssoc }; + +enum class ParenType { Left, + Right }; + +struct expression_token { + using pointer = std::unique_ptr; + + virtual ~expression_token() = default; + + virtual pointer clone() const = 0; + + virtual TokenType type() const = 0; +}; + +struct num_token final : public expression_token { + num_token(real_t n) : + num{ n } { + } + + pointer clone() const override { + return std::make_unique(*this); + } + + TokenType type() const override { + return TokenType::Number; + } + + real_t num; +}; + +struct op_token final : public expression_token { + op_token(OpType o) : + op{ o } { + std::tuple props; + switch (op) { + case OpType::Add: + props = std::make_tuple('+', 0, OpArity::Binary, + OpAssoc::Left); + break; + case OpType::Sub: + props = std::make_tuple('-', 0, OpArity::Binary, + OpAssoc::Left); + break; + case OpType::Mul: + props = std::make_tuple('*', 1, OpArity::Binary, + OpAssoc::Left); + break; + case OpType::Div: + props = std::make_tuple('/', 1, OpArity::Binary, + OpAssoc::Left); + break; + case OpType::Mod: + props = std::make_tuple('%', 1, OpArity::Binary, + OpAssoc::Left); + break; + case OpType::UPlus: + props = std::make_tuple('+', 2, OpArity::Unary, + OpAssoc::Right); + break; + case OpType::UMinus: + props = std::make_tuple('-', 2, OpArity::Unary, + OpAssoc::Right); + break; + case OpType::Exp: + props = std::make_tuple('^', 2, OpArity::Binary, + OpAssoc::Right); + break; + } + symbol = std::get<0>(props); + prec = std::get<1>(props); + arity = std::get<2>(props); + assoc = std::get<3>(props); + } + + pointer clone() const override { + return std::make_unique(*this); + } + + TokenType type() const override { + return TokenType::Operator; + } + + bool operator<(const op_token &that) const { + return this->prec < that.prec; + } + + bool operator<=(const op_token &that) const { + return this->prec <= that.prec; + } + + OpType op; + char symbol; + int prec; + OpArity arity; + OpAssoc assoc; +}; + +struct paren_token final : public expression_token { + paren_token(ParenType p) : + paren{ p }, pchar{ ParenType::Left == paren ? '(' : ')' } { + } + + pointer clone() const override { + return std::make_unique(*this); + } + + TokenType type() const override { + return TokenType::Parenthesis; + } + + ParenType paren; + char pchar; +}; + +struct var_token final : public expression_token { + var_token(const str_t &v) : + var{ v } { + } + + pointer clone() const override { + return std::make_unique(*this); + } + + TokenType type() const override { + return TokenType::Variable; + } + + str_t var; +}; + +} // namespace genalyzer_impl namespace genalyzer_impl { - bool is_binary_operator(char c) - { - return ('*' == c) || ('/' == c) || ('%' == c) || ('^' == c); - } - - bool is_operator(char c) - { - return ('+' == c) || ('-' == c) || ('*' == c) || ('/' == c) || ('%' == c) || ('^' == c); - } - - bool is_variable(const str_t& s) - { - static const std::regex re ("[[:alpha:]][[:alnum:]_]*"); - return std::regex_match(s, re); - } - - void operator<<(expression::token_vector& tokens, real_t n) - { - tokens.push_back(std::make_unique(n)); - } - - void operator<<(expression::token_vector& tokens, OpType o) - { - tokens.push_back(std::make_unique(o)); - } - - void operator<<(expression::token_vector& tokens, ParenType p) - { - tokens.push_back(std::make_unique(p)); - } - - void operator<<(expression::token_vector& tokens, const str_t& v) - { - tokens.push_back(std::make_unique(v)); - } - - void push_back_operator(expression::token_vector& tokens, char c, OpArity arity) - { - OpType op = OpType::Add; - switch (c) - { - case '+' : op = (OpArity::Unary == arity) ? OpType::UPlus : OpType::Add; break; - case '-' : op = (OpArity::Unary == arity) ? OpType::UMinus : OpType::Sub; break; - case '*' : op = OpType::Mul; break; - case '/' : op = OpType::Div; break; - case '%' : op = OpType::Mod; break; - case '^' : op = OpType::Exp; break; - } - tokens << op; - } - - expression::var_set get_vars(const expression::token_vector& tokens) - { - expression::var_set vars; - for (const expression::token_ptr& token : tokens) { - if (TokenType::Variable == token->type()) { - auto& v = static_cast(*token); - vars.insert(v.var); - } - } - return vars; - } - - void validate_postfix(const expression::token_vector& tokens) - { - str_t msg = "validate_postfix : "; - std::stack operands; - for (const expression::token_ptr& token : tokens) { - switch (token->type()) - { - case TokenType::Number : - case TokenType::Variable : - operands.push(0.0); - break; - case TokenType::Operator : { - auto& op = static_cast(*token); - if (OpArity::Unary == op.arity) { - if (operands.size() < 1) { - throw runtime_error(msg + "stack underflow"); - } - } else { - if (operands.size() < 2) { - throw runtime_error(msg + "stack underflow"); - } else { - operands.pop(); - } - } - break; - } - case TokenType::Parenthesis : - throw runtime_error(msg + "parenthesis found in postfix"); - } - } - if (1 < operands.size()) { - throw runtime_error(msg + "stack overflow"); - } - } - - expression::token_vector infix_to_postfix(const expression::token_vector& infix_tokens) - { - /* - * Uses Edsger Dijkstra's Shunting Yard algorithm to convert infix to postfix - * https://en.wikipedia.org/wiki/Shunting-yard_algorithm - * https://www.chris-j.co.uk/parsing.php - */ - expression::token_vector postfix_tokens; - if (infix_tokens.empty()) { - return postfix_tokens; - } - std::stack op_stack; - for (const expression::token_ptr& token : infix_tokens) { - switch (token->type()) - { - case TokenType::Number : - case TokenType::Variable : - postfix_tokens.push_back(token->clone()); - break; - case TokenType::Operator : { - auto& op1 = static_cast(*token); - while (!op_stack.empty()) { - if (TokenType::Parenthesis == op_stack.top()->type()) { - break; - } - auto& op2 = static_cast(*op_stack.top()); - if ((OpAssoc::Left == op1.assoc && op1 <= op2) || - (OpAssoc::Right == op1.assoc && op1 < op2)) { - postfix_tokens.push_back(op_stack.top()->clone()); - op_stack.pop(); - } else { - break; - } - } - op_stack.push(token->clone()); - break; - } case TokenType::Parenthesis : { - auto& p1 = static_cast(*token); - if (ParenType::Left == p1.paren) { - op_stack.push(token->clone()); - } else { - while (!op_stack.empty()) { - if (TokenType::Parenthesis == op_stack.top()->type()) { - auto& p2 = static_cast(*op_stack.top()); - if (ParenType::Left == p2.paren) { - op_stack.pop(); - break; - } - } - postfix_tokens.push_back(op_stack.top()->clone()); - op_stack.pop(); - } - } - break; - } - } - } - while (!op_stack.empty()) { - postfix_tokens.push_back(op_stack.top()->clone()); - op_stack.pop(); - } - validate_postfix(postfix_tokens); - return postfix_tokens; - } - - str_t to_string(const expression::token_vector& tokens, FPFormat fmt, int prec) - { - std::ostringstream ss; - for (const expression::token_ptr& token : tokens) { - switch (token->type()) - { - case TokenType::Number : { - auto& t = static_cast(*token); - ss << genalyzer_impl::to_string(t.num, fmt, prec); - break; - } - case TokenType::Operator : { - auto& t = static_cast(*token); - ss << t.symbol; - break; - } - case TokenType::Parenthesis : { - auto& t = static_cast(*token); - ss << t.pchar; - break; - } - case TokenType::Variable : { - auto& t = static_cast(*token); - ss << t.var; - break; - } - } - } - return ss.str(); - } - - expression::token_vector tokenize_infix(const str_t& infix_string) - { - expression::token_vector tokens; - char c = 0; - std::istringstream ss (infix_string); - int open_parens = 0; - const char* syntax_error = "tokenize_infix : syntax error"; - while (ss >> c) { - // Number - if (std::isdigit(c) || '.' == c) { - if (!tokens.empty()) { - TokenType previous = tokens.back()->type(); - if (TokenType::Number == previous || TokenType::Variable == previous) { - tokens.clear(); - throw runtime_error(syntax_error); - } else if (TokenType::Parenthesis == previous) { - auto& p = static_cast(*tokens.back()); - if (ParenType::Right == p.paren) { - tokens << OpType::Mul; - } - } - } - ss.unget(); - real_t num = 0.0; - ss >> num; +bool is_binary_operator(char c) { + return ('*' == c) || ('/' == c) || ('%' == c) || ('^' == c); +} + +bool is_operator(char c) { + return ('+' == c) || ('-' == c) || ('*' == c) || ('/' == c) || + ('%' == c) || ('^' == c); +} + +bool is_variable(const str_t &s) { + static const std::regex re("[[:alpha:]][[:alnum:]_]*"); + return std::regex_match(s, re); +} + +void operator<<(expression::token_vector &tokens, real_t n) { + tokens.push_back(std::make_unique(n)); +} + +void operator<<(expression::token_vector &tokens, OpType o) { + tokens.push_back(std::make_unique(o)); +} + +void operator<<(expression::token_vector &tokens, ParenType p) { + tokens.push_back(std::make_unique(p)); +} + +void operator<<(expression::token_vector &tokens, const str_t &v) { + tokens.push_back(std::make_unique(v)); +} + +void push_back_operator(expression::token_vector &tokens, char c, OpArity arity) { + OpType op = OpType::Add; + switch (c) { + case '+': + op = (OpArity::Unary == arity) ? OpType::UPlus : OpType::Add; + break; + case '-': + op = (OpArity::Unary == arity) ? OpType::UMinus : OpType::Sub; + break; + case '*': + op = OpType::Mul; + break; + case '/': + op = OpType::Div; + break; + case '%': + op = OpType::Mod; + break; + case '^': + op = OpType::Exp; + break; + } + tokens << op; +} + +expression::var_set get_vars(const expression::token_vector &tokens) { + expression::var_set vars; + for (const expression::token_ptr &token : tokens) { + if (TokenType::Variable == token->type()) { + auto &v = static_cast(*token); + vars.insert(v.var); + } + } + return vars; +} + +void validate_postfix(const expression::token_vector &tokens) { + str_t msg = "validate_postfix : "; + std::stack operands; + for (const expression::token_ptr &token : tokens) { + switch (token->type()) { + case TokenType::Number: + case TokenType::Variable: + operands.push(0.0); + break; + case TokenType::Operator: { + auto &op = static_cast(*token); + if (OpArity::Unary == op.arity) { + if (operands.size() < 1) { + throw runtime_error(msg + + "stack underflow"); + } + } else { + if (operands.size() < 2) { + throw runtime_error(msg + + "stack underflow"); + } else { + operands.pop(); + } + } + break; + } + case TokenType::Parenthesis: + throw runtime_error(msg + + "parenthesis found in postfix"); + } + } + if (1 < operands.size()) { + throw runtime_error(msg + "stack overflow"); + } +} + +expression::token_vector +infix_to_postfix(const expression::token_vector &infix_tokens) { + /* + * Uses Edsger Dijkstra's Shunting Yard algorithm to convert infix to postfix + * https://en.wikipedia.org/wiki/Shunting-yard_algorithm + * https://www.chris-j.co.uk/parsing.php + */ + expression::token_vector postfix_tokens; + if (infix_tokens.empty()) { + return postfix_tokens; + } + std::stack op_stack; + for (const expression::token_ptr &token : infix_tokens) { + switch (token->type()) { + case TokenType::Number: + case TokenType::Variable: + postfix_tokens.push_back(token->clone()); + break; + case TokenType::Operator: { + auto &op1 = static_cast(*token); + while (!op_stack.empty()) { + if (TokenType::Parenthesis == + op_stack.top()->type()) { + break; + } + auto &op2 = static_cast( + *op_stack.top()); + if ((OpAssoc::Left == op1.assoc && + op1 <= op2) || + (OpAssoc::Right == op1.assoc && + op1 < op2)) { + postfix_tokens.push_back( + op_stack.top()->clone()); + op_stack.pop(); + } else { + break; + } + } + op_stack.push(token->clone()); + break; + } + case TokenType::Parenthesis: { + auto &p1 = static_cast(*token); + if (ParenType::Left == p1.paren) { + op_stack.push(token->clone()); + } else { + while (!op_stack.empty()) { + if (TokenType::Parenthesis == + op_stack.top()->type()) { + auto &p2 = static_cast< + const paren_token &>( + *op_stack.top()); + if (ParenType::Left == + p2.paren) { + op_stack.pop(); + break; + } + } + postfix_tokens.push_back( + op_stack.top()->clone()); + op_stack.pop(); + } + } + break; + } + } + } + while (!op_stack.empty()) { + postfix_tokens.push_back(op_stack.top()->clone()); + op_stack.pop(); + } + validate_postfix(postfix_tokens); + return postfix_tokens; +} + +str_t to_string(const expression::token_vector &tokens, FPFormat fmt, int prec) { + std::ostringstream ss; + for (const expression::token_ptr &token : tokens) { + switch (token->type()) { + case TokenType::Number: { + auto &t = static_cast(*token); + ss << genalyzer_impl::to_string(t.num, fmt, prec); + break; + } + case TokenType::Operator: { + auto &t = static_cast(*token); + ss << t.symbol; + break; + } + case TokenType::Parenthesis: { + auto &t = static_cast(*token); + ss << t.pchar; + break; + } + case TokenType::Variable: { + auto &t = static_cast(*token); + ss << t.var; + break; + } + } + } + return ss.str(); +} + +expression::token_vector tokenize_infix(const str_t &infix_string) { + expression::token_vector tokens; + char c = 0; + std::istringstream ss(infix_string); + int open_parens = 0; + const char *syntax_error = "tokenize_infix : syntax error"; + while (ss >> c) { + // Number + if (std::isdigit(c) || '.' == c) { + if (!tokens.empty()) { + TokenType previous = tokens.back()->type(); + if (TokenType::Number == previous || + TokenType::Variable == previous) { + tokens.clear(); + throw runtime_error(syntax_error); + } else if (TokenType::Parenthesis == previous) { + auto &p = + static_cast( + *tokens.back()); + if (ParenType::Right == p.paren) { + tokens << OpType::Mul; + } + } + } + ss.unget(); + real_t num = 0.0; + ss >> num; #if defined(__APPLE__) - if (!ss){ - // Clang doesn't support stringstream to double if contains characters - // Need to manually convert - std::string tmp = ss.str(); - ss.clear(); // clear error flags - // Remove all non-numeric characters - tmp.erase(std::remove_if(tmp.begin(), tmp.end(), [](char c) { return !(std::isdigit(c) || c == '.'); }), tmp.end()); - if (tmp.empty()) { - throw runtime_error("tokenize_infix : invalid numeric value"); - } - num = std::stod(tmp); - } + if (!ss) { + // Clang doesn't support stringstream to double if contains characters + // Need to manually convert + std::string tmp = ss.str(); + ss.clear(); // clear error flags + // Remove all non-numeric characters + tmp.erase(std::remove_if( + tmp.begin(), tmp.end(), + [](char c) { + return !(std::isdigit( + c) || + c == '.'); + }), + tmp.end()); + if (tmp.empty()) { + throw runtime_error( + "tokenize_infix : invalid numeric value"); + } + num = std::stod(tmp); + } #endif - if (ss) { - tokens << num; - } else { - throw runtime_error("tokenize_infix : invalid numeric value"); - } - } - // Operator - else if (is_operator(c)) { - if (is_binary_operator(c)) { - if (tokens.empty()) { - throw runtime_error(syntax_error); - } - TokenType previous = tokens.back()->type(); - if (TokenType::Operator == previous) { - tokens.clear(); - throw runtime_error(syntax_error); - } else if (TokenType::Parenthesis == previous) { - auto& p = static_cast(*tokens.back()); - if (ParenType::Left == p.paren) { - tokens.clear(); - throw runtime_error(syntax_error); - } - } - push_back_operator(tokens, c, OpArity::Binary); - } else { - OpArity arity = OpArity::Unary; - if (!tokens.empty()) { - TokenType previous = tokens.back()->type(); - if (TokenType::Number == previous || TokenType::Variable == previous) { - arity = OpArity::Binary; - } else if (TokenType::Parenthesis == previous) { - auto& p = static_cast(*tokens.back()); - if (ParenType::Right == p.paren) { - arity = OpArity::Binary; - } - } else if (TokenType::Operator == previous) { - auto& o = static_cast(*tokens.back()); - if ('+' == o.symbol || '-' == o.symbol) { - tokens.clear(); - throw runtime_error(syntax_error); - } - } - } - push_back_operator(tokens, c, arity); - } - } - // Left Parenthesis - else if ('(' == c) { - if (!tokens.empty()) { - TokenType previous = tokens.back()->type(); - if (TokenType::Number == previous || TokenType::Variable == previous) { - tokens << OpType::Mul; - } else if (TokenType::Parenthesis == previous) { - auto& p = static_cast(*tokens.back()); - if (ParenType::Right == p.paren) { - tokens << OpType::Mul; - } - } - } - tokens << ParenType::Left; - open_parens += 1; - } - // Right Parenthesis - else if (')' == c) { - if (tokens.empty()) { - throw runtime_error(syntax_error); - } - TokenType previous = tokens.back()->type(); - if (TokenType::Operator == previous) { - tokens.clear(); - throw runtime_error(syntax_error); - } else if (TokenType::Parenthesis == previous) { - auto& p = static_cast(*tokens.back()); - if (ParenType::Left == p.paren) { - tokens.clear(); - throw runtime_error(syntax_error); - } - } - tokens << ParenType::Right; - open_parens -= 1; - } - // Variable - else if (std::isalpha(c)) { - if (!tokens.empty()) { - TokenType previous = tokens.back()->type(); - if (TokenType::Number == previous) { - tokens << OpType::Mul; - } else if (TokenType::Parenthesis == previous) { - auto& p = static_cast(*tokens.back()); - if (ParenType::Right == p.paren) { - tokens << OpType::Mul; - } - } else if (TokenType::Variable == previous) { - tokens.clear(); - throw runtime_error(syntax_error); - } - } - str_t var (1, c); - while (ss.get(c)) { - if (std::isalnum(c) || '_' == c) { - var.push_back(c); - } else { - ss.unget(); - break; - } - } - if (is_variable(var)) { - tokens << var; - } else { - throw runtime_error("tokenize_infix : invalid variable name"); - } - } - // Invalid - else { - tokens.clear(); - throw runtime_error("tokenize_infix : invalid token"); - } - } - // Check for unmatched parentheses - if (0 != open_parens) { - throw runtime_error("tokenize_infix : expression has unmatched parentheses"); - } - // Last token must not be an operator or left parenthesis - if (tokens.empty()) { - throw runtime_error("tokenize_infix : expression has no tokens"); - } else { - TokenType last = tokens.back()->type(); - if (TokenType::Operator == last) { - tokens.clear(); - throw runtime_error(syntax_error); - } else if (TokenType::Parenthesis == last) { - auto& p = static_cast(*tokens.back()); - if (ParenType::Left == p.paren) { - tokens.clear(); - throw runtime_error("tokenize_infix : expression has unmatched parentheses"); - } - } - } - return tokens; - } + if (ss) { + tokens << num; + } else { + throw runtime_error( + "tokenize_infix : invalid numeric value"); + } + } + // Operator + else if (is_operator(c)) { + if (is_binary_operator(c)) { + if (tokens.empty()) { + throw runtime_error(syntax_error); + } + TokenType previous = tokens.back()->type(); + if (TokenType::Operator == previous) { + tokens.clear(); + throw runtime_error(syntax_error); + } else if (TokenType::Parenthesis == previous) { + auto &p = + static_cast( + *tokens.back()); + if (ParenType::Left == p.paren) { + tokens.clear(); + throw runtime_error( + syntax_error); + } + } + push_back_operator(tokens, c, OpArity::Binary); + } else { + OpArity arity = OpArity::Unary; + if (!tokens.empty()) { + TokenType previous = + tokens.back()->type(); + if (TokenType::Number == previous || + TokenType::Variable == previous) { + arity = OpArity::Binary; + } else if (TokenType::Parenthesis == + previous) { + auto &p = static_cast< + const paren_token &>( + *tokens.back()); + if (ParenType::Right == + p.paren) { + arity = OpArity::Binary; + } + } else if (TokenType::Operator == + previous) { + auto &o = static_cast< + const op_token &>( + *tokens.back()); + if ('+' == o.symbol || + '-' == o.symbol) { + tokens.clear(); + throw runtime_error( + syntax_error); + } + } + } + push_back_operator(tokens, c, arity); + } + } + // Left Parenthesis + else if ('(' == c) { + if (!tokens.empty()) { + TokenType previous = tokens.back()->type(); + if (TokenType::Number == previous || + TokenType::Variable == previous) { + tokens << OpType::Mul; + } else if (TokenType::Parenthesis == previous) { + auto &p = + static_cast( + *tokens.back()); + if (ParenType::Right == p.paren) { + tokens << OpType::Mul; + } + } + } + tokens << ParenType::Left; + open_parens += 1; + } + // Right Parenthesis + else if (')' == c) { + if (tokens.empty()) { + throw runtime_error(syntax_error); + } + TokenType previous = tokens.back()->type(); + if (TokenType::Operator == previous) { + tokens.clear(); + throw runtime_error(syntax_error); + } else if (TokenType::Parenthesis == previous) { + auto &p = static_cast( + *tokens.back()); + if (ParenType::Left == p.paren) { + tokens.clear(); + throw runtime_error(syntax_error); + } + } + tokens << ParenType::Right; + open_parens -= 1; + } + // Variable + else if (std::isalpha(c)) { + if (!tokens.empty()) { + TokenType previous = tokens.back()->type(); + if (TokenType::Number == previous) { + tokens << OpType::Mul; + } else if (TokenType::Parenthesis == previous) { + auto &p = + static_cast( + *tokens.back()); + if (ParenType::Right == p.paren) { + tokens << OpType::Mul; + } + } else if (TokenType::Variable == previous) { + tokens.clear(); + throw runtime_error(syntax_error); + } + } + str_t var(1, c); + while (ss.get(c)) { + if (std::isalnum(c) || '_' == c) { + var.push_back(c); + } else { + ss.unget(); + break; + } + } + if (is_variable(var)) { + tokens << var; + } else { + throw runtime_error( + "tokenize_infix : invalid variable name"); + } + } + // Invalid + else { + tokens.clear(); + throw runtime_error("tokenize_infix : invalid token"); + } + } + // Check for unmatched parentheses + if (0 != open_parens) { + throw runtime_error( + "tokenize_infix : expression has unmatched parentheses"); + } + // Last token must not be an operator or left parenthesis + if (tokens.empty()) { + throw runtime_error( + "tokenize_infix : expression has no tokens"); + } else { + TokenType last = tokens.back()->type(); + if (TokenType::Operator == last) { + tokens.clear(); + throw runtime_error(syntax_error); + } else if (TokenType::Parenthesis == last) { + auto &p = static_cast( + *tokens.back()); + if (ParenType::Left == p.paren) { + tokens.clear(); + throw runtime_error( + "tokenize_infix : expression has unmatched parentheses"); + } + } + } + return tokens; +} } // namespace genalyzer_impl namespace genalyzer_impl { // expression class - expression::expression(const str_t& infix_string) - : m_infix_tokens (tokenize_infix(infix_string)) - {} - - expression::~expression() = default; - - bool expression::depends_on(const var_set& vars) const - { - var_set expr_vars = get_vars(m_infix_tokens); - for (const str_t& v : vars) { - if (expr_vars.find(v) != expr_vars.end()) { - return true; - } - } - return false; - } - - real_t expression::evaluate(const var_map& vars) const - { - str_t msg = "expression::evaluate : "; - str_t missing_var = vars_defined(vars); - if (!missing_var.empty()) { - throw runtime_error(msg + "expression depends on undefined variable, '" + missing_var + "'"); - } - token_vector postfix_tokens = infix_to_postfix(m_infix_tokens); - if (postfix_tokens.empty()) { - throw runtime_error(msg + "empty expression"); - } - std::stack operands; - for (const token_ptr& token : postfix_tokens) { - switch (token->type()) - { - case TokenType::Number : { - auto& t = static_cast(*token); - operands.push(t.num); - break; - } - case TokenType::Variable : { - auto& t = static_cast(*token); - operands.push(vars.at(t.var)); - break; - } - case TokenType::Operator : { - auto& t = static_cast(*token); - real_t result = 0.0; - if (OpArity::Unary == t.arity) { - real_t value = operands.top(); - operands.pop(); - switch (t.op) - { - case OpType::UPlus : - result = value; - break; - case OpType::UMinus : - result = -value; - break; - default: - break; - } - } else { - real_t rval = operands.top(); - operands.pop(); - real_t lval = operands.top(); - operands.pop(); - switch (t.op) - { - case OpType::Add : - result = lval + rval; - break; - case OpType::Sub : - result = lval - rval; - break; - case OpType::Mul : - result = lval * rval; - break; - case OpType::Div : - if (0.0 == rval) { - throw runtime_error(msg + "divide by 0"); - } - result = lval / rval; - break; - case OpType::Mod : - if (0.0 == rval) { - throw runtime_error(msg + "divide by 0"); - } - result = std::fmod(lval, rval); - break; - case OpType::Exp : - result = std::pow(lval, rval); - break; - default: - break; - } - } - operands.push(result); - break; - } - default: - break; - } - } - if (1 != operands.size()) { - throw runtime_error(msg + "stack error"); - } - return operands.top(); - } - - str_t expression::to_postfix_string(FPFormat fmt, int prec) const - { - token_vector postfix_tokens = infix_to_postfix(m_infix_tokens); - return genalyzer_impl::to_string(postfix_tokens, fmt, prec); - } - - str_t expression::to_string(FPFormat fmt, int prec) const - { - return genalyzer_impl::to_string(m_infix_tokens, fmt, prec); - } - - expression::var_set expression::vars() const - { - return get_vars(m_infix_tokens); - } - - str_t expression::vars_defined(const var_map& vars) const - { - var_set expr_vars = get_vars(m_infix_tokens); - for (const str_t& v : expr_vars) { - if (vars.end() == vars.find(v)) { - return v; - } - } - return ""; - } - +expression::expression(const str_t &infix_string) : + m_infix_tokens(tokenize_infix(infix_string)) { +} + +expression::~expression() = default; + +bool expression::depends_on(const var_set &vars) const { + var_set expr_vars = get_vars(m_infix_tokens); + for (const str_t &v : vars) { + if (expr_vars.find(v) != expr_vars.end()) { + return true; + } + } + return false; +} + +real_t expression::evaluate(const var_map &vars) const { + str_t msg = "expression::evaluate : "; + str_t missing_var = vars_defined(vars); + if (!missing_var.empty()) { + throw runtime_error( + msg + "expression depends on undefined variable, '" + + missing_var + "'"); + } + token_vector postfix_tokens = infix_to_postfix(m_infix_tokens); + if (postfix_tokens.empty()) { + throw runtime_error(msg + "empty expression"); + } + std::stack operands; + for (const token_ptr &token : postfix_tokens) { + switch (token->type()) { + case TokenType::Number: { + auto &t = static_cast(*token); + operands.push(t.num); + break; + } + case TokenType::Variable: { + auto &t = static_cast(*token); + operands.push(vars.at(t.var)); + break; + } + case TokenType::Operator: { + auto &t = static_cast(*token); + real_t result = 0.0; + if (OpArity::Unary == t.arity) { + real_t value = operands.top(); + operands.pop(); + switch (t.op) { + case OpType::UPlus: + result = value; + break; + case OpType::UMinus: + result = -value; + break; + default: + break; + } + } else { + real_t rval = operands.top(); + operands.pop(); + real_t lval = operands.top(); + operands.pop(); + switch (t.op) { + case OpType::Add: + result = lval + rval; + break; + case OpType::Sub: + result = lval - rval; + break; + case OpType::Mul: + result = lval * rval; + break; + case OpType::Div: + if (0.0 == rval) { + throw runtime_error( + msg + "divide by 0"); + } + result = lval / rval; + break; + case OpType::Mod: + if (0.0 == rval) { + throw runtime_error( + msg + "divide by 0"); + } + result = std::fmod(lval, rval); + break; + case OpType::Exp: + result = std::pow(lval, rval); + break; + default: + break; + } + } + operands.push(result); + break; + } + default: + break; + } + } + if (1 != operands.size()) { + throw runtime_error(msg + "stack error"); + } + return operands.top(); +} + +str_t expression::to_postfix_string(FPFormat fmt, int prec) const { + token_vector postfix_tokens = infix_to_postfix(m_infix_tokens); + return genalyzer_impl::to_string(postfix_tokens, fmt, prec); +} + +str_t expression::to_string(FPFormat fmt, int prec) const { + return genalyzer_impl::to_string(m_infix_tokens, fmt, prec); +} + +expression::var_set expression::vars() const { + return get_vars(m_infix_tokens); +} + +str_t expression::vars_defined(const var_map &vars) const { + var_set expr_vars = get_vars(m_infix_tokens); + for (const str_t &v : expr_vars) { + if (vars.end() == vars.find(v)) { + return v; + } + } + return ""; +} + } // namespace genalyzer_impl \ No newline at end of file diff --git a/src/formatted_data.cpp b/src/formatted_data.cpp index a084680..7ff0bc0 100644 --- a/src/formatted_data.cpp +++ b/src/formatted_data.cpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #include "formatted_data.hpp" #include @@ -6,66 +9,62 @@ namespace genalyzer_impl { - str_t table( - const std::vector& header_rows, - const std::vector& data_rows, - int col_margin, - bool show_border, - bool show_col_sep - ) - { - std::vector all_rows (header_rows); - all_rows.insert(all_rows.end(), data_rows.begin(), data_rows.end()); - // Determine number of columns - size_t ncols = 0; - for (const str_vector& row : all_rows) { - ncols = std::max(ncols, row.size()); - } - if (0 == ncols) { - return ""; - } - // Determine max data width in each column - std::vector col_widths (ncols, 0); - for (str_vector& row : all_rows) { - for (size_t col = 0; col < row.size(); ++col) { - col_widths[col] = std::max(col_widths[col], row[col].size()); - } - // Add missing columns to row - row.resize(ncols, ""); - } - // Setup - col_margin = std::max(0, std::min(col_margin, 9)); - str_t col_pad = str_t(static_cast(col_margin), ' '); - str_t col_div = col_pad + (show_col_sep ? '|' : ' ') + col_pad; - str_t left_border = (show_border ? '|' : ' ') + col_pad; - str_t right_border = col_pad + (show_border ? '|' : ' '); - size_t total_width = left_border.size() + (ncols - 1) * col_div.size() + right_border.size(); - for (size_t w : col_widths) { - total_width += w; - } - str_t h_border = show_border ? (str_t(total_width, '=') + '\n') : ""; - str_t h_div = header_rows.empty() ? "" : (str_t(total_width, '=') + '\n'); - // Generate table - std::ostringstream ss; - ss << h_border; - for (size_t row = 0; row < all_rows.size(); ++row) { - if (header_rows.size() == row) { - ss << h_div; - } - ss << left_border; - const str_vector& data = all_rows[row]; - for (size_t col = 0; col < ncols; ++col) { - ss << std::setw(static_cast(col_widths[col])) - << std::left - << data[col]; - if (col + 1 < ncols) { - ss << col_div; - } - } - ss << right_border << '\n'; - } - ss << h_border; - return ss.str(); - } +str_t table(const std::vector &header_rows, + const std::vector &data_rows, int col_margin, + bool show_border, bool show_col_sep) { + std::vector all_rows(header_rows); + all_rows.insert(all_rows.end(), data_rows.begin(), data_rows.end()); + // Determine number of columns + size_t ncols = 0; + for (const str_vector &row : all_rows) { + ncols = std::max(ncols, row.size()); + } + if (0 == ncols) { + return ""; + } + // Determine max data width in each column + std::vector col_widths(ncols, 0); + for (str_vector &row : all_rows) { + for (size_t col = 0; col < row.size(); ++col) { + col_widths[col] = + std::max(col_widths[col], row[col].size()); + } + // Add missing columns to row + row.resize(ncols, ""); + } + // Setup + col_margin = std::max(0, std::min(col_margin, 9)); + str_t col_pad = str_t(static_cast(col_margin), ' '); + str_t col_div = col_pad + (show_col_sep ? '|' : ' ') + col_pad; + str_t left_border = (show_border ? '|' : ' ') + col_pad; + str_t right_border = col_pad + (show_border ? '|' : ' '); + size_t total_width = left_border.size() + (ncols - 1) * col_div.size() + + right_border.size(); + for (size_t w : col_widths) { + total_width += w; + } + str_t h_border = show_border ? (str_t(total_width, '=') + '\n') : ""; + str_t h_div = header_rows.empty() ? "" : (str_t(total_width, '=') + '\n'); + // Generate table + std::ostringstream ss; + ss << h_border; + for (size_t row = 0; row < all_rows.size(); ++row) { + if (header_rows.size() == row) { + ss << h_div; + } + ss << left_border; + const str_vector &data = all_rows[row]; + for (size_t col = 0; col < ncols; ++col) { + ss << std::setw(static_cast(col_widths[col])) + << std::left << data[col]; + if (col + 1 < ncols) { + ss << col_div; + } + } + ss << right_border << '\n'; + } + ss << h_border; + return ss.str(); +} } // namespace genalyzer_impl diff --git a/src/fourier_analysis.cpp b/src/fourier_analysis.cpp index 9833b5b..be7451c 100644 --- a/src/fourier_analysis.cpp +++ b/src/fourier_analysis.cpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #include "fourier_analysis.hpp" #include "array_ops.hpp" @@ -14,1528 +17,1757 @@ namespace genalyzer_impl { - namespace { - - struct fraction - { - int num; - int den; - str_t term; - - fraction(int n, int d, const str_t& var = "") - { - if (!(1 <= n && 1 <= d && n < d)) { - throw runtime_error("Invalid fraction"); - } - int gcd = std::gcd(n, d); - num = n / gcd; - den = d / gcd; - if (1 == num && !var.empty()) { - term = var; - } else { - term = std::to_string(num) + var; - } - term += '/' + std::to_string(den); - } - - }; // struct fraction - - bool operator<(const fraction& lhs, const fraction& rhs) - { - // Based on numeric value, this operator would: - // return lhs.num * rhs.den < lhs.den * rhs.num; - // But in this implementation of Fourier analysis, fractions are grouped by - // denominator, in increasing order: - if (lhs.den < rhs.den) { - return true; - } else { - return (lhs.den == rhs.den) && (lhs.num < rhs.num); - } - } - - str_t negate(const str_t& expr, bool neg) - { - return neg ? ("-(" + expr + ')') : expr; - } - - } // namespace anonymous - - const fourier_analysis::min_max_def_t fourier_analysis::mmd_hd = { 1, 99, 6 }; - const fourier_analysis::min_max_def_t fourier_analysis::mmd_imd = { 1, 9, 3 }; - const fourier_analysis::min_max_def_t fourier_analysis::mmd_wo = { 1, 9, 1 }; - const fourier_analysis::min_max_def_t fourier_analysis::mmd_ssb = { 0, 1 << 29, 0 }; +namespace { + +struct fraction { + int num; + int den; + str_t term; + + fraction(int n, int d, const str_t &var = "") { + if (!(1 <= n && 1 <= d && n < d)) { + throw runtime_error("Invalid fraction"); + } + int gcd = std::gcd(n, d); + num = n / gcd; + den = d / gcd; + if (1 == num && !var.empty()) { + term = var; + } else { + term = std::to_string(num) + var; + } + term += '/' + std::to_string(den); + } + +}; // struct fraction + +bool operator<(const fraction &lhs, const fraction &rhs) { + // Based on numeric value, this operator would: + // return lhs.num * rhs.den < lhs.den * rhs.num; + // But in this implementation of Fourier analysis, fractions are grouped by + // denominator, in increasing order: + if (lhs.den < rhs.den) { + return true; + } else { + return (lhs.den == rhs.den) && (lhs.num < rhs.num); + } +} + +str_t negate(const str_t &expr, bool neg) { + return neg ? ("-(" + expr + ')') : expr; +} + +} // namespace + +const fourier_analysis::min_max_def_t fourier_analysis::mmd_hd = { 1, 99, 6 }; +const fourier_analysis::min_max_def_t fourier_analysis::mmd_imd = { 1, 9, 3 }; +const fourier_analysis::min_max_def_t fourier_analysis::mmd_wo = { 1, 9, 1 }; +const fourier_analysis::min_max_def_t fourier_analysis::mmd_ssb = { 0, 1 << 29, + 0 }; } // namespace genalyzer_impl namespace genalyzer_impl { // Constructors, Destructor, and Assignment - fourier_analysis::fourier_analysis() - : object {}, - // Parameters - clk_as_noise (false), - dc_as_dist (false), - en_conv_offset (false), - en_fund_images (true), - en_quad_errors (false), - ilv_as_noise (false), - m_hd (std::get<2>(mmd_hd)), - m_imd (std::get<2>(mmd_imd)), - m_wo (std::get<2>(mmd_wo)), - m_ssb_def (std::get<2>(mmd_ssb)), - m_ssb_dc (-1), - m_ssb_sig (-1), - m_ssb_wo (-1), - m_ab_center ("0"), - m_ab_width ("fdata"), - m_fdata ("fs"), - m_fsample ("1"), - m_fshift ("0"), - m_clk (), - m_ilv (), - // Components - m_user_keys (), - m_user_comps (), - // Variables - m_user_vars () - {} - - fourier_analysis::fourier_analysis(const fourier_analysis& obj) - : object {}, - // Parameters - clk_as_noise (obj.clk_as_noise), - dc_as_dist (obj.dc_as_dist), - en_conv_offset (obj.en_conv_offset), - en_fund_images (obj.en_fund_images), - en_quad_errors (obj.en_quad_errors), - ilv_as_noise (obj.ilv_as_noise), - m_hd (obj.m_hd), - m_imd (obj.m_imd), - m_wo (obj.m_wo), - m_ssb_def (obj.m_ssb_def), - m_ssb_dc (obj.m_ssb_dc), - m_ssb_sig (obj.m_ssb_sig), - m_ssb_wo (obj.m_ssb_wo), - m_ab_center (obj.m_ab_center), - m_ab_width (obj.m_ab_width), - m_fdata (obj.m_fdata), - m_fsample (obj.m_fsample), - m_fshift (obj.m_fshift), - m_clk (obj.m_clk), - m_ilv (obj.m_ilv), - // Components - m_user_keys (obj.m_user_keys), - m_user_comps (), - // Variables - m_user_vars (obj.m_user_vars) - { - for (const str_t& key : m_user_keys) { - m_user_comps[key] = obj.m_user_comps.at(key)->clone(); - } - } - - fourier_analysis::fourier_analysis(fourier_analysis&& obj) - : object {}, - // Parameters - clk_as_noise (obj.clk_as_noise), - dc_as_dist (obj.dc_as_dist), - en_conv_offset (obj.en_conv_offset), - en_fund_images (obj.en_fund_images), - en_quad_errors (obj.en_quad_errors), - ilv_as_noise (obj.ilv_as_noise), - m_hd (obj.m_hd), - m_imd (obj.m_imd), - m_wo (obj.m_wo), - m_ssb_def (obj.m_ssb_def), - m_ssb_dc (obj.m_ssb_dc), - m_ssb_sig (obj.m_ssb_sig), - m_ssb_wo (obj.m_ssb_wo), - m_ab_center (obj.m_ab_center), - m_ab_width (obj.m_ab_width), - m_fdata (obj.m_fdata), - m_fsample (obj.m_fsample), - m_fshift (obj.m_fshift), - m_clk (std::move(obj.m_clk)), - m_ilv (std::move(obj.m_ilv)), - // Components - m_user_keys (std::move(obj.m_user_keys)), - m_user_comps (std::move(obj.m_user_comps)), - // Variables - m_user_vars (std::move(obj.m_user_vars)) - {} - - fourier_analysis& fourier_analysis::operator=(const fourier_analysis& obj) - { - if (&obj != this) { - fourier_analysis the_copy (obj); - std::swap(the_copy, *this); - } - return *this; - } - - fourier_analysis& fourier_analysis::operator=(fourier_analysis&& obj) - { - // Parameters - std::swap(clk_as_noise , obj.clk_as_noise); - std::swap(dc_as_dist , obj.dc_as_dist); - std::swap(en_conv_offset , obj.en_conv_offset); - std::swap(en_fund_images , obj.en_fund_images); - std::swap(en_quad_errors , obj.en_quad_errors); - std::swap(ilv_as_noise , obj.ilv_as_noise); - std::swap(m_hd , obj.m_hd); - std::swap(m_imd , obj.m_imd); - std::swap(m_wo , obj.m_wo); - std::swap(m_ssb_def , obj.m_ssb_def); - std::swap(m_ssb_dc , obj.m_ssb_dc); - std::swap(m_ssb_sig , obj.m_ssb_sig); - std::swap(m_ssb_wo , obj.m_ssb_wo); - std::swap(m_ab_center , obj.m_ab_center); - std::swap(m_ab_width , obj.m_ab_width); - std::swap(m_fdata , obj.m_fdata); - std::swap(m_fsample , obj.m_fsample); - std::swap(m_fshift , obj.m_fshift); - std::swap(m_clk , obj.m_clk); - std::swap(m_ilv , obj.m_ilv); - // Components - std::swap(m_user_keys , obj.m_user_keys); - std::swap(m_user_comps , obj.m_user_comps); - // Variables - std::swap(m_user_vars , obj.m_user_vars); - return *this; - } - -} // namespace genalyzer_impl - Constructors, Destructor, and Assignment +fourier_analysis::fourier_analysis() : + object{}, + // Parameters + clk_as_noise(false), + dc_as_dist(false), + en_conv_offset(false), + en_fund_images(true), + en_quad_errors(false), + ilv_as_noise(false), + m_hd(std::get<2>(mmd_hd)), + m_imd(std::get<2>(mmd_imd)), + m_wo(std::get<2>(mmd_wo)), + m_ssb_def(std::get<2>(mmd_ssb)), + m_ssb_dc(-1), + m_ssb_sig(-1), + m_ssb_wo(-1), + m_ab_center("0"), + m_ab_width("fdata"), + m_fdata("fs"), + m_fsample("1"), + m_fshift("0"), + m_clk(), + m_ilv(), + // Components + m_user_keys(), + m_user_comps(), + // Variables + m_user_vars() { +} + +fourier_analysis::fourier_analysis(const fourier_analysis &obj) : + object{}, + // Parameters + clk_as_noise(obj.clk_as_noise), + dc_as_dist(obj.dc_as_dist), + en_conv_offset(obj.en_conv_offset), + en_fund_images(obj.en_fund_images), + en_quad_errors(obj.en_quad_errors), + ilv_as_noise(obj.ilv_as_noise), + m_hd(obj.m_hd), + m_imd(obj.m_imd), + m_wo(obj.m_wo), + m_ssb_def(obj.m_ssb_def), + m_ssb_dc(obj.m_ssb_dc), + m_ssb_sig(obj.m_ssb_sig), + m_ssb_wo(obj.m_ssb_wo), + m_ab_center(obj.m_ab_center), + m_ab_width(obj.m_ab_width), + m_fdata(obj.m_fdata), + m_fsample(obj.m_fsample), + m_fshift(obj.m_fshift), + m_clk(obj.m_clk), + m_ilv(obj.m_ilv), + // Components + m_user_keys(obj.m_user_keys), + m_user_comps(), + // Variables + m_user_vars(obj.m_user_vars) { + for (const str_t &key : m_user_keys) { + m_user_comps[key] = obj.m_user_comps.at(key)->clone(); + } +} + +fourier_analysis::fourier_analysis(fourier_analysis &&obj) : + object{}, + // Parameters + clk_as_noise(obj.clk_as_noise), + dc_as_dist(obj.dc_as_dist), + en_conv_offset(obj.en_conv_offset), + en_fund_images(obj.en_fund_images), + en_quad_errors(obj.en_quad_errors), + ilv_as_noise(obj.ilv_as_noise), + m_hd(obj.m_hd), + m_imd(obj.m_imd), + m_wo(obj.m_wo), + m_ssb_def(obj.m_ssb_def), + m_ssb_dc(obj.m_ssb_dc), + m_ssb_sig(obj.m_ssb_sig), + m_ssb_wo(obj.m_ssb_wo), + m_ab_center(obj.m_ab_center), + m_ab_width(obj.m_ab_width), + m_fdata(obj.m_fdata), + m_fsample(obj.m_fsample), + m_fshift(obj.m_fshift), + m_clk(std::move(obj.m_clk)), + m_ilv(std::move(obj.m_ilv)), + // Components + m_user_keys(std::move(obj.m_user_keys)), + m_user_comps(std::move(obj.m_user_comps)), + // Variables + m_user_vars(std::move(obj.m_user_vars)) { +} + +fourier_analysis &fourier_analysis::operator=(const fourier_analysis &obj) { + if (&obj != this) { + fourier_analysis the_copy(obj); + std::swap(the_copy, *this); + } + return *this; +} + +fourier_analysis &fourier_analysis::operator=(fourier_analysis &&obj) { + // Parameters + std::swap(clk_as_noise, obj.clk_as_noise); + std::swap(dc_as_dist, obj.dc_as_dist); + std::swap(en_conv_offset, obj.en_conv_offset); + std::swap(en_fund_images, obj.en_fund_images); + std::swap(en_quad_errors, obj.en_quad_errors); + std::swap(ilv_as_noise, obj.ilv_as_noise); + std::swap(m_hd, obj.m_hd); + std::swap(m_imd, obj.m_imd); + std::swap(m_wo, obj.m_wo); + std::swap(m_ssb_def, obj.m_ssb_def); + std::swap(m_ssb_dc, obj.m_ssb_dc); + std::swap(m_ssb_sig, obj.m_ssb_sig); + std::swap(m_ssb_wo, obj.m_ssb_wo); + std::swap(m_ab_center, obj.m_ab_center); + std::swap(m_ab_width, obj.m_ab_width); + std::swap(m_fdata, obj.m_fdata); + std::swap(m_fsample, obj.m_fsample); + std::swap(m_fshift, obj.m_fshift); + std::swap(m_clk, obj.m_clk); + std::swap(m_ilv, obj.m_ilv); + // Components + std::swap(m_user_keys, obj.m_user_keys); + std::swap(m_user_comps, obj.m_user_comps); + // Variables + std::swap(m_user_vars, obj.m_user_vars); + return *this; +} + +} // namespace genalyzer_impl namespace genalyzer_impl { // Analysis - fourier_analysis_results fourier_analysis::analyze( - const real_t* in_data, - const size_t in_size, - const size_t nfft, - FreqAxisType axis_type - ) const - { - check_array("", "input array", in_data, in_size); - std::vector msq; // used only if in_data is complex - const real_t* msq_data = nullptr; - size_t msq_size = 0; - const cplx_t* fft_data = nullptr; - size_t fft_size = 0; - if (in_size == nfft || // Real data, complex analysis - in_size == nfft / 2 + 1) { // Real data, real analysis - // input array is mean-square FFT data (phase not available) - msq_data = in_data; - msq_size = in_size; - } else if (in_size == nfft * 2 || // Complex data, complex analysis - in_size == (nfft / 2 + 1) * 2) { // Complex data, real analysis - // input array is interleaved Re/Im FFT data - msq_size = in_size / 2; - msq = std::vector(msq_size); - norm(in_data, in_size, msq.data(), msq.size()); - msq_data = msq.data(); - fft_data = reinterpret_cast(in_data); - fft_size = in_size / 2; - } else { - throw runtime_error("Mismatch between data size and NFFT"); - } - fourier_analysis_results results = analyze_impl(msq_data, msq_size, nfft, axis_type, fft_data, fft_size); - return results; - } - -} // namespace genalyzer_impl - Analysis +fourier_analysis_results fourier_analysis::analyze(const real_t *in_data, + const size_t in_size, + const size_t nfft, + FreqAxisType axis_type) const { + check_array("", "input array", in_data, in_size); + std::vector msq; // used only if in_data is complex + const real_t *msq_data = nullptr; + size_t msq_size = 0; + const cplx_t *fft_data = nullptr; + size_t fft_size = 0; + if (in_size == nfft || // Real data, complex analysis + in_size == nfft / 2 + 1) { // Real data, real analysis + // input array is mean-square FFT data (phase not available) + msq_data = in_data; + msq_size = in_size; + } else if (in_size == nfft * 2 || // Complex data, complex analysis + in_size == + (nfft / 2 + 1) * 2) { // Complex data, real analysis + // input array is interleaved Re/Im FFT data + msq_size = in_size / 2; + msq = std::vector(msq_size); + norm(in_data, in_size, msq.data(), msq.size()); + msq_data = msq.data(); + fft_data = reinterpret_cast(in_data); + fft_size = in_size / 2; + } else { + throw runtime_error("Mismatch between data size and NFFT"); + } + fourier_analysis_results results = analyze_impl( + msq_data, msq_size, nfft, axis_type, fft_data, fft_size); + return results; +} + +} // namespace genalyzer_impl namespace genalyzer_impl { // Component Definition - void fourier_analysis::add_fixed_tone( - const str_t& key, FACompTag tag, const str_t& freq, int ssb) - { - if_key_not_available_throw(key); - expression fe (freq); - ssb = limit_ssb(ssb, -1); - m_user_keys.push_back(key); - m_user_comps.insert({key, std::make_unique( - tag, fe.to_string(FPFormat::Eng), ssb)}); - } - - void fourier_analysis::add_max_tone( - const str_t& key, FACompTag tag, const str_t& center, const str_t& width, int ssb) - { - if (FACompTag::Signal == tag || FACompTag::UserDist == tag || FACompTag::Noise == tag) { - if_key_not_available_throw(key); - expression ce (center); - expression we (width); - ssb = limit_ssb(ssb, -1); - m_user_keys.push_back(key); - m_user_comps.insert({key, std::make_unique( - tag, ce.to_string(FPFormat::Eng), we.to_string(FPFormat::Eng), ssb)}); - } else { - throw runtime_error("tag must be one of {" - + fa_comp_tag_map.at(to_int(FACompTag::Signal)) + ", " - + fa_comp_tag_map.at(to_int(FACompTag::UserDist)) + ", " - + fa_comp_tag_map.at(to_int(FACompTag::Noise)) + '}'); - } - } - - void fourier_analysis::remove_comp(const str_t& key) - { - if (is_comp(key)) { - m_user_comps.erase(key); - m_user_keys.erase(std::remove(m_user_keys.begin(), m_user_keys.end(), key), m_user_keys.end()); - } - } - -} // namespace genalyzer_impl - Component Definition +void fourier_analysis::add_fixed_tone(const str_t &key, FACompTag tag, + const str_t &freq, int ssb) { + if_key_not_available_throw(key); + expression fe(freq); + ssb = limit_ssb(ssb, -1); + m_user_keys.push_back(key); + m_user_comps.insert( + { key, std::make_unique(tag, fe.to_string(FPFormat::Eng), ssb) }); +} + +void fourier_analysis::add_max_tone(const str_t &key, FACompTag tag, + const str_t ¢er, const str_t &width, + int ssb) { + if (FACompTag::Signal == tag || FACompTag::UserDist == tag || + FACompTag::Noise == tag) { + if_key_not_available_throw(key); + expression ce(center); + expression we(width); + ssb = limit_ssb(ssb, -1); + m_user_keys.push_back(key); + m_user_comps.insert( + { key, std::make_unique(tag, ce.to_string(FPFormat::Eng), we.to_string(FPFormat::Eng), ssb) }); + } else { + throw runtime_error( + "tag must be one of {" + + fa_comp_tag_map.at(to_int(FACompTag::Signal)) + ", " + + fa_comp_tag_map.at(to_int(FACompTag::UserDist)) + ", " + + fa_comp_tag_map.at(to_int(FACompTag::Noise)) + '}'); + } +} + +void fourier_analysis::remove_comp(const str_t &key) { + if (is_comp(key)) { + m_user_comps.erase(key); + m_user_keys.erase(std::remove(m_user_keys.begin(), + m_user_keys.end(), key), + m_user_keys.end()); + } +} + +} // namespace genalyzer_impl namespace genalyzer_impl { // Configuration - namespace { - - void fa_set_expr(const str_t& name, str_t& m_expr, const str_t& expr, const expression::var_set& disallowed) - { - expression e (expr); - if (e.depends_on(disallowed)) { - std::ostringstream ss (name); - ss << " may not depend on"; - for (const str_t& s : disallowed) { - ss << " '" << s << "',"; - } - ss.seekp(-1, std::ios_base::end); - throw runtime_error(ss.str()); - } else { - m_expr = e.to_string(FPFormat::Eng); - } - } - - } // namespace anonymous - - int fourier_analysis::ssb(FASsb group) const - { - switch (group) - { - case FASsb::DC : - return m_ssb_dc; - case FASsb::Signal : - return m_ssb_sig; - case FASsb::WO : - return m_ssb_wo; - default : - return m_ssb_def; - } - } - - void fourier_analysis::set_analysis_band(const str_t& center, const str_t& width) - { - fa_set_expr("ab_center", m_ab_center, center, {}); - fa_set_expr("ab_width", m_ab_width, width, {}); - } - - void fourier_analysis::set_clk(const std::set& clk) - { - m_clk.clear(); - for (int n : clk) { - if (2 <= n && n <= 256) { - m_clk.insert(n); - } - } - } - - void fourier_analysis::set_fdata(const str_t& expr) - { - expression::var_set disallowed {"fbin", "fdata", "fshift"}; - fa_set_expr("fdata", m_fdata, expr, disallowed); - } - - void fourier_analysis::set_fsample(const str_t& expr) - { - expression::var_set disallowed {"fbin", "fdata", "fs", "fshift"}; - fa_set_expr("fsample", m_fsample, expr, disallowed); - } - - void fourier_analysis::set_fshift(const str_t& expr) - { - expression::var_set disallowed {"fshift"}; - fa_set_expr("fshift", m_fshift, expr, disallowed); - } - - void fourier_analysis::set_hd(int n) - { - m_hd = std::clamp(n, std::get<0>(mmd_hd), std::get<1>(mmd_hd)); - } - - void fourier_analysis::set_ilv(const std::set& ilv) - { - m_ilv.clear(); - for (int n : ilv) { - if (2 <= n && n <= 64) { - m_ilv.insert(n); - } - } - } - - void fourier_analysis::set_imd(int n) - { - m_imd = std::clamp(n, std::get<0>(mmd_imd), std::get<1>(mmd_imd)); - } - - void fourier_analysis::set_ssb(FASsb group, int ssb) - { - switch (group) - { - case FASsb::DC : - m_ssb_dc = limit_ssb(ssb, -1); - break; - case FASsb::Signal : - m_ssb_sig = limit_ssb(ssb, -1); - break; - case FASsb::WO : - m_ssb_wo = limit_ssb(ssb, -1); - break; - default : - m_ssb_def = limit_ssb(ssb, std::get<0>(mmd_ssb)); - break; - } - } - - void fourier_analysis::set_var(const str_t& key, real_t x) - { - if (!is_var(key)) { - if_key_not_available_throw(key); - } - if (!std::isfinite(x)) { - throw runtime_error("got non-finite value"); - } - m_user_vars[key] = x; - } - - void fourier_analysis::set_wo(int n) - { - m_wo = std::clamp(n, std::get<0>(mmd_wo), std::get<1>(mmd_wo)); - } - -} // namespace genalyzer_impl - Configuration +namespace { + +void fa_set_expr(const str_t &name, str_t &m_expr, const str_t &expr, + const expression::var_set &disallowed) { + expression e(expr); + if (e.depends_on(disallowed)) { + std::ostringstream ss(name); + ss << " may not depend on"; + for (const str_t &s : disallowed) { + ss << " '" << s << "',"; + } + ss.seekp(-1, std::ios_base::end); + throw runtime_error(ss.str()); + } else { + m_expr = e.to_string(FPFormat::Eng); + } +} + +} // namespace + +int fourier_analysis::ssb(FASsb group) const { + switch (group) { + case FASsb::DC: + return m_ssb_dc; + case FASsb::Signal: + return m_ssb_sig; + case FASsb::WO: + return m_ssb_wo; + default: + return m_ssb_def; + } +} + +void fourier_analysis::set_analysis_band(const str_t ¢er, + const str_t &width) { + fa_set_expr("ab_center", m_ab_center, center, {}); + fa_set_expr("ab_width", m_ab_width, width, {}); +} + +void fourier_analysis::set_clk(const std::set &clk) { + m_clk.clear(); + for (int n : clk) { + if (2 <= n && n <= 256) { + m_clk.insert(n); + } + } +} + +void fourier_analysis::set_fdata(const str_t &expr) { + expression::var_set disallowed{ "fbin", "fdata", "fshift" }; + fa_set_expr("fdata", m_fdata, expr, disallowed); +} + +void fourier_analysis::set_fsample(const str_t &expr) { + expression::var_set disallowed{ "fbin", "fdata", "fs", "fshift" }; + fa_set_expr("fsample", m_fsample, expr, disallowed); +} + +void fourier_analysis::set_fshift(const str_t &expr) { + expression::var_set disallowed{ "fshift" }; + fa_set_expr("fshift", m_fshift, expr, disallowed); +} + +void fourier_analysis::set_hd(int n) { + m_hd = std::clamp(n, std::get<0>(mmd_hd), std::get<1>(mmd_hd)); +} + +void fourier_analysis::set_ilv(const std::set &ilv) { + m_ilv.clear(); + for (int n : ilv) { + if (2 <= n && n <= 64) { + m_ilv.insert(n); + } + } +} + +void fourier_analysis::set_imd(int n) { + m_imd = std::clamp(n, std::get<0>(mmd_imd), std::get<1>(mmd_imd)); +} + +void fourier_analysis::set_ssb(FASsb group, int ssb) { + switch (group) { + case FASsb::DC: + m_ssb_dc = limit_ssb(ssb, -1); + break; + case FASsb::Signal: + m_ssb_sig = limit_ssb(ssb, -1); + break; + case FASsb::WO: + m_ssb_wo = limit_ssb(ssb, -1); + break; + default: + m_ssb_def = limit_ssb(ssb, std::get<0>(mmd_ssb)); + break; + } +} + +void fourier_analysis::set_var(const str_t &key, real_t x) { + if (!is_var(key)) { + if_key_not_available_throw(key); + } + if (!std::isfinite(x)) { + throw runtime_error("got non-finite value"); + } + m_user_vars[key] = x; +} + +void fourier_analysis::set_wo(int n) { + m_wo = std::clamp(n, std::get<0>(mmd_wo), std::get<1>(mmd_wo)); +} + +} // namespace genalyzer_impl namespace genalyzer_impl { // Key Queries - bool fourier_analysis::is_reserved(const str_t& key) - { - if (reserved_keys.end() != reserved_keys.find(key)) { - return true; - } - for (const str_t& pat : reserved_patterns) { - std::regex re (pat); - if (std::regex_match(key, re)) { - return true; - } - } - return false; - } - - bool fourier_analysis::is_valid(const str_t& key) - { - std::regex re (key_pattern); - return std::regex_match(key, re); - } - -} // namespace genalyzer_impl - Key Queries +bool fourier_analysis::is_reserved(const str_t &key) { + if (reserved_keys.end() != reserved_keys.find(key)) { + return true; + } + for (const str_t &pat : reserved_patterns) { + std::regex re(pat); + if (std::regex_match(key, re)) { + return true; + } + } + return false; +} + +bool fourier_analysis::is_valid(const str_t &key) { + std::regex re(key_pattern); + return std::regex_match(key, re); +} + +} // namespace genalyzer_impl namespace genalyzer_impl { // Other Member Functions - - str_t fourier_analysis::flat_tone_key(const str_t& key, int result_index) - { - fa_tone_result_map.contains(result_index, true); - return key + flat_key_coupler + fa_tone_result_map.at(result_index); - } - - std::pair fourier_analysis::split_key(const str_t& key) - { - std::pair keys {"", ""}; - size_t pos = key.find(flat_key_coupler); - if (std::string::npos == pos) { - keys.first = key; - } else { - keys.first = key.substr(0, pos); - keys.second = key.substr(pos + flat_key_coupler.length()); - } - return keys; - } - - str_t fourier_analysis::preview(bool cplx) const - { - const comp_data_t comp_data = generate_comps(cplx); - const str_vector& keys = std::get<0>(comp_data); - const comp_map& comps = std::get<1>(comp_data); - std::vector header {{"Index", "Key", "Type", "Tag", "Spec"}}; - std::vector data; - int i = 0; - for (const str_t& key : keys) { - const comp_ptr& comp = comps.at(key); - str_vector row {std::to_string(i), key}; - row.push_back(fa_comp_type_map.at(to_int(comp->type))); - row.push_back(fa_comp_tag_map.at(to_int(comp->tag))); - row.push_back(comp->spec()); - data.push_back(row); - ++i; - } - return table(header, data, 2, true, true); - } - - void fourier_analysis::reset() - { - fourier_analysis new_obj {}; - std::swap(new_obj, *this); - } - - namespace { - - bool is_cplx_analysis(size_t in_size, size_t nfft) - { - bool cplx = false; - if (in_size == nfft || in_size == nfft * 2) { - cplx = true; - } else if (!(in_size == nfft / 2 + 1 || in_size == (nfft / 2 + 1) * 2)) { - throw runtime_error("Invalid combination of data size and NFFT"); - } - return cplx; - } - - } // namespace anonymous - - std::vector fourier_analysis::result_key_lengths(size_t in_size, size_t nfft) const - { - bool cplx = is_cplx_analysis(in_size, nfft); - const comp_data_t comp_data = generate_comps(cplx); - const str_vector& comp_keys = std::get<0>(comp_data); - const size_t num_result_keys = static_cast(FAResult::__SIZE__); - const size_t num_tone_result_keys = static_cast(FAToneResult::__SIZE__); - size_t total_keys = num_result_keys + num_tone_result_keys * comp_keys.size(); - std::vector key_lengths (total_keys); - size_t i = 0; - for (int j = 0; j < static_cast(num_result_keys); ++j) { - key_lengths[i] = fa_result_map.at(j).length(); - i += 1; - } - size_t key_coupler_len = flat_key_coupler.length(); - std::vector tone_result_key_lengths (num_tone_result_keys, key_coupler_len); - for (int j = 0; j < static_cast(num_tone_result_keys); ++j) { - tone_result_key_lengths[j] += fa_tone_result_map.at(j).length(); - } - for (const str_t& ckey : comp_keys) { - const size_t ckey_len = ckey.length(); - for (size_t rkey_len : tone_result_key_lengths) { - key_lengths[i] = ckey_len + rkey_len; - i += 1; - } - } - return key_lengths; - } - - size_t fourier_analysis::results_size(size_t in_size, size_t nfft) const - { - bool cplx = is_cplx_analysis(in_size, nfft); - const comp_data_t comp_data = generate_comps(cplx); - const str_vector& keys = std::get<0>(comp_data); - size_t size = fa_result_map.size(); - size += fa_tone_result_map.size() * keys.size(); - return size; - } - -} // namespace genalyzer_impl - Other Member Functions + +str_t fourier_analysis::flat_tone_key(const str_t &key, int result_index) { + fa_tone_result_map.contains(result_index, true); + return key + flat_key_coupler + fa_tone_result_map.at(result_index); +} + +std::pair fourier_analysis::split_key(const str_t &key) { + std::pair keys{ "", "" }; + size_t pos = key.find(flat_key_coupler); + if (std::string::npos == pos) { + keys.first = key; + } else { + keys.first = key.substr(0, pos); + keys.second = key.substr(pos + flat_key_coupler.length()); + } + return keys; +} + +str_t fourier_analysis::preview(bool cplx) const { + const comp_data_t comp_data = generate_comps(cplx); + const str_vector &keys = std::get<0>(comp_data); + const comp_map &comps = std::get<1>(comp_data); + std::vector header{ { "Index", "Key", "Type", "Tag", + "Spec" } }; + std::vector data; + int i = 0; + for (const str_t &key : keys) { + const comp_ptr &comp = comps.at(key); + str_vector row{ std::to_string(i), key }; + row.push_back(fa_comp_type_map.at(to_int(comp->type))); + row.push_back(fa_comp_tag_map.at(to_int(comp->tag))); + row.push_back(comp->spec()); + data.push_back(row); + ++i; + } + return table(header, data, 2, true, true); +} + +void fourier_analysis::reset() { + fourier_analysis new_obj{}; + std::swap(new_obj, *this); +} + +namespace { + +bool is_cplx_analysis(size_t in_size, size_t nfft) { + bool cplx = false; + if (in_size == nfft || in_size == nfft * 2) { + cplx = true; + } else if (!(in_size == nfft / 2 + 1 || + in_size == (nfft / 2 + 1) * 2)) { + throw runtime_error( + "Invalid combination of data size and NFFT"); + } + return cplx; +} + +} // namespace + +std::vector fourier_analysis::result_key_lengths(size_t in_size, + size_t nfft) const { + bool cplx = is_cplx_analysis(in_size, nfft); + const comp_data_t comp_data = generate_comps(cplx); + const str_vector &comp_keys = std::get<0>(comp_data); + const size_t num_result_keys = static_cast(FAResult::__SIZE__); + const size_t num_tone_result_keys = + static_cast(FAToneResult::__SIZE__); + size_t total_keys = + num_result_keys + num_tone_result_keys * comp_keys.size(); + std::vector key_lengths(total_keys); + size_t i = 0; + for (int j = 0; j < static_cast(num_result_keys); ++j) { + key_lengths[i] = fa_result_map.at(j).length(); + i += 1; + } + size_t key_coupler_len = flat_key_coupler.length(); + std::vector tone_result_key_lengths(num_tone_result_keys, + key_coupler_len); + for (int j = 0; j < static_cast(num_tone_result_keys); ++j) { + tone_result_key_lengths[j] += fa_tone_result_map.at(j).length(); + } + for (const str_t &ckey : comp_keys) { + const size_t ckey_len = ckey.length(); + for (size_t rkey_len : tone_result_key_lengths) { + key_lengths[i] = ckey_len + rkey_len; + i += 1; + } + } + return key_lengths; +} + +size_t fourier_analysis::results_size(size_t in_size, size_t nfft) const { + bool cplx = is_cplx_analysis(in_size, nfft); + const comp_data_t comp_data = generate_comps(cplx); + const str_vector &keys = std::get<0>(comp_data); + size_t size = fa_result_map.size(); + size += fa_tone_result_map.size() * keys.size(); + return size; +} + +} // namespace genalyzer_impl namespace genalyzer_impl { // Virtual Function Overrides - bool fourier_analysis::equals_impl(const object& that_obj) const - { - if (ObjectType::FourierAnalysis != that_obj.object_type()) { - return false; - } - auto& that = static_cast(that_obj); - if ( (this->clk_as_noise != that.clk_as_noise ) || - (this->dc_as_dist != that.dc_as_dist ) || - (this->en_conv_offset != that.en_conv_offset) || - (this->en_fund_images != that.en_fund_images) || - (this->en_quad_errors != that.en_quad_errors) || - (this->ilv_as_noise != that.ilv_as_noise ) ) { - return false; - } - if ( (this->m_hd != that.m_hd ) || - (this->m_imd != that.m_imd ) || - (this->m_wo != that.m_wo ) || - (this->m_ssb_def != that.m_ssb_def ) || - (this->m_ssb_dc != that.m_ssb_dc ) || - (this->m_ssb_sig != that.m_ssb_sig ) || - (this->m_ssb_wo != that.m_ssb_wo ) ) { - return false; - } - if ( (this->m_ab_center != that.m_ab_center ) || - (this->m_ab_width != that.m_ab_width ) || - (this->m_fdata != that.m_fdata ) || - (this->m_fsample != that.m_fsample ) || - (this->m_fshift != that.m_fshift ) ) { - return false; - } - if ( (this->m_clk != that.m_clk ) || - (this->m_ilv != that.m_ilv ) || - (this->m_user_keys != that.m_user_keys ) || - (this->m_user_vars != that.m_user_vars ) ) { - return false; - } - for (const str_t& key : m_user_keys) { - const fourier_analysis_component& this_comp = *this->m_user_comps.at(key); - const fourier_analysis_component& that_comp = *that.m_user_comps.at(key); - if (!this_comp.equals(that_comp)) { - return false; - } - } - return true; - } - - str_t fourier_analysis::to_string_impl() const - { - return "=====\nFIXME\n=====\n"; - } - +bool fourier_analysis::equals_impl(const object &that_obj) const { + if (ObjectType::FourierAnalysis != that_obj.object_type()) { + return false; + } + auto &that = static_cast(that_obj); + if ((this->clk_as_noise != that.clk_as_noise) || + (this->dc_as_dist != that.dc_as_dist) || + (this->en_conv_offset != that.en_conv_offset) || + (this->en_fund_images != that.en_fund_images) || + (this->en_quad_errors != that.en_quad_errors) || + (this->ilv_as_noise != that.ilv_as_noise)) { + return false; + } + if ((this->m_hd != that.m_hd) || (this->m_imd != that.m_imd) || + (this->m_wo != that.m_wo) || (this->m_ssb_def != that.m_ssb_def) || + (this->m_ssb_dc != that.m_ssb_dc) || + (this->m_ssb_sig != that.m_ssb_sig) || + (this->m_ssb_wo != that.m_ssb_wo)) { + return false; + } + if ((this->m_ab_center != that.m_ab_center) || + (this->m_ab_width != that.m_ab_width) || + (this->m_fdata != that.m_fdata) || + (this->m_fsample != that.m_fsample) || + (this->m_fshift != that.m_fshift)) { + return false; + } + if ((this->m_clk != that.m_clk) || (this->m_ilv != that.m_ilv) || + (this->m_user_keys != that.m_user_keys) || + (this->m_user_vars != that.m_user_vars)) { + return false; + } + for (const str_t &key : m_user_keys) { + const fourier_analysis_component &this_comp = + *this->m_user_comps.at(key); + const fourier_analysis_component &that_comp = + *that.m_user_comps.at(key); + if (!this_comp.equals(that_comp)) { + return false; + } + } + return true; +} + +str_t fourier_analysis::to_string_impl() const { + return "=====\nFIXME\n=====\n"; +} + } // namespace genalyzer_impl namespace genalyzer_impl { // Non-Public - const str_t fourier_analysis::key_pattern = "[[:alpha:]][[:alnum:]_]*"; - - const str_t fourier_analysis::wo_pattern = "^wo[1-9]?$"; - - const std::set fourier_analysis::reserved_keys = { - "co", // comp/var : converter offset - "dc", // comp : DC - "fbin", // var : frequency bin size - "fdata", // var : data rate - "fs", // var : sample rate - "fshift" // var : shift frequency - }; - - const str_vector fourier_analysis::reserved_patterns = { - fourier_analysis::wo_pattern - }; - - const str_t fourier_analysis::flat_key_coupler = ":"; - - void fourier_analysis::add_comp(str_vector& keys, comp_map& comps, const str_t& k, comp_ptr c) - { - if (comps.find(k) != comps.end()) { - throw runtime_error("fourier_analysis::add_comp : key '" + k + "' already exists"); - } - keys.push_back(k); - comps.insert({k, std::move(c)}); - } - - int fourier_analysis::limit_ssb(int ssb, int lower_limit) { - lower_limit = (lower_limit < 0) ? -1 : std::get<0>(mmd_ssb); - return std::clamp(ssb, lower_limit, std::get<1>(mmd_ssb)); - } - - fourier_analysis::comp_data_t fourier_analysis::generate_comps(bool cplx) const - { - bool find_fi = en_fund_images && cplx; - bool find_qe = en_quad_errors && cplx; - comp_data_t comp_data; - str_vector& keys = std::get<0>(comp_data); - comp_map& comps = std::get<1>(comp_data); - std::set& ilos_clk_keys = std::get<2>(comp_data); - str_t key = ""; - int ssb = 0; - // DC and Converter Offset Components - ssb = (m_ssb_dc < 0) ? m_ssb_def : m_ssb_dc; - add_comp(keys, comps, "dc", fa_dc::create(ssb)); - if (en_conv_offset) { - add_comp(keys, comps, "co", fa_fixed_tone::create(FACompTag::UserDist, "0", ssb)); - } - // Interleaving Offset and Clock Components - std::set ilos_clk_terms; - std::set ilv_terms; - for (int x : m_ilv) { - for (int i = 1; i <= x / 2; ++i) { - ilv_terms.emplace(i, x, "fs"); - ilos_clk_terms.emplace(i, x, "fs"); - } - } - std::set clk_terms; - for (int x : m_clk) - { - for (int i = 1; i <= x / 2; ++i) { - if (1 == std::gcd(i, x)) { - clk_terms.emplace(i, x, "fs"); - ilos_clk_terms.emplace(i, x, "fs"); - } - } - } - for (const fraction& f : ilos_clk_terms) { - key = f.term; - if (ilv_terms.end() != ilv_terms.find(f)) { - bool is_also_clk = clk_terms.end() != clk_terms.find(f); - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::ILOS, key, m_ssb_def)); - if (is_also_clk) { - ilos_clk_keys.insert(key); - } - if (cplx && "fs/2" != key) { - key.insert(0, 1, '-'); - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::ILOS, key, m_ssb_def)); - if (is_also_clk) { - ilos_clk_keys.insert(key); - } - } - } else { - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::CLK, key, m_ssb_def)); - if (cplx && "fs/2" != key) { - key.insert(0, 1, '-'); - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::CLK, key, m_ssb_def)); - } - } - } - // User and Auto Components - str_vector fund_keys; - int def_sig_ssb = (m_ssb_sig < 0) ? m_ssb_def : m_ssb_sig; - for (const str_t& ukey : m_user_keys) { - const comp_ptr& comp = m_user_comps.at(ukey); - int def_user_ssb = (FACompTag::Signal == comp->tag) ? def_sig_ssb : m_ssb_def; - if (FACompType::FixedTone == comp->type) { - const auto& c = static_cast(*comp); - ssb = (c.ssb < 0) ? def_user_ssb : c.ssb; - add_comp(keys, comps, ukey, fa_fixed_tone::create(c.tag, c.freq, ssb)); - } else if (FACompType::MaxTone == comp->type) { - const auto& c = static_cast(*comp); - ssb = (c.ssb < 0) ? def_user_ssb : c.ssb; - add_comp(keys, comps, ukey, fa_max_tone::create(c.tag, c.center, c.width, ssb)); - } else { - throw runtime_error("fourier_analysis::generate_comps : unsupported component type"); - } - if (FACompTag::Signal != comp->tag) { - continue; - } - fund_keys.push_back(ukey); - ssb = m_ssb_def; - // Fundamental Image Component - if (find_fi) { - key = '-' + ukey; - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::HD, key, ssb)); - } - // Harmonic Distortion Components - for (int i = 2; i <= m_hd; ++i) { - if (is_even(i)) { - // even order - key = std::to_string(i) + ukey; - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::HD, key, ssb)); - if (cplx) { - key.insert(0, 1, '-'); - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::HD, key, ssb)); - } - } else { - // odd order - // real data: j = +i - // cplx data: j = -i for 3, 7, 11... - // j = +i for 5, 9, 13... - int j = (cplx && is_odd(i / 2)) ? -i : i; - key = std::to_string(j) + ukey; - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::HD, key, ssb)); - if (find_qe) { - key = std::to_string(-j) + ukey; - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::HD, key, ssb)); - } - } - } - // Interleaving Gain and Timing Components - for (const fraction& f : ilv_terms) { - key = ukey + '+' + f.term; - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::ILGT, key, ssb)); - if ("fs/2" != f.term) { - key = ukey + '-' + f.term; - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::ILGT, key, ssb)); - } - if (find_qe) { - key = negate(ukey + '+' + f.term, true); - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::ILGT, key, ssb)); - if ("fs/2" != f.term) { - key = negate(ukey + '-' + f.term, true); - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::ILGT, key, ssb)); - } - } - } - // Intermodulation Distorion Components - for (const str_t& ka : fund_keys) { - if (ka == ukey) { - continue; - } - const str_t& kb = ukey; - for (int order = 2; order <= m_imd; ++order) { - int group = is_even(order) ? 0 : 1; - int pp = 0; - int qq = 0; - str_t p = ""; - str_t q = ""; - for (; group <= order; group += 2) { - if (group < order) { - // form: p * kx MINUS q * ky - pp = (order + group) / 2; - qq = order - pp; - p = (1 == pp) ? "" : std::to_string(pp); - q = (1 == qq) ? "" : std::to_string(qq); - if (0 == group) { - key = p + kb + '-' + q + ka; - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::IMD, key, ssb)); - if (cplx) { - key = negate(key, true); - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::IMD, key, ssb)); - } - } else if (is_even(order)) { - // even order - key = p + ka + '-' + q + kb; - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::IMD, key, ssb)); - key = p + kb + '-' + q + ka; - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::IMD, key, ssb)); - if (cplx) { - key = negate(p + ka + '-' + q + kb, true); - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::IMD, key, ssb)); - key = negate(p + kb + '-' + q + ka, true); - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::IMD, key, ssb)); - } - } else { - // odd order - bool neg = cplx && is_odd(group / 2); - key = negate(p + ka + '-' + q + kb, neg); - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::IMD, key, ssb)); - key = negate(p + kb + '-' + q + ka, neg); - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::IMD, key, ssb)); - if (cplx) { - key = negate(p + ka + '-' + q + kb, !neg); - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::IMD, key, ssb)); - key = negate(p + kb + '-' + q + ka, !neg); - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::IMD, key, ssb)); - } - } - } else { // group == order - // form: p * kx PLUS q * ky - if (is_even(order)) { - // even order - for (qq = 1; qq < group; ++qq) { - pp = order - qq; - p = (1 == pp) ? "" : std::to_string(pp); - q = (1 == qq) ? "" : std::to_string(qq); - key = p + ka + '+' + q + kb; - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::IMD, key, ssb)); - } - if (cplx) { - for (pp = 1; pp < group; ++pp) { - qq = order - pp; - p = (1 == pp) ? "" : std::to_string(pp); - q = (1 == qq) ? "" : std::to_string(qq); - key = negate(p + ka + '+' + q + kb, true); - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::IMD, key, ssb)); - } - } - } else { - // odd order - bool neg = cplx && is_odd(group / 2); - for (qq = 1; qq < group; ++qq) { - pp = order - qq; - p = (1 == pp) ? "" : std::to_string(pp); - q = (1 == qq) ? "" : std::to_string(qq); - key = negate(p + ka + '+' + q + kb, neg); - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::IMD, key, ssb)); - } - if (find_qe) { - for (pp = 1; pp < group; ++pp) { - qq = order - pp; - p = (1 == pp) ? "" : std::to_string(pp); - q = (1 == qq) ? "" : std::to_string(qq); - key = negate(p + ka + '+' + q + kb, !neg); - add_comp(keys, comps, key, fa_fixed_tone::create(FACompTag::IMD, key, ssb)); - } - } - } - } - } - } - } - } - // WO Components - ssb = (m_ssb_wo < 0) ? m_ssb_def : m_ssb_wo; - if (1 == m_wo) { - add_comp(keys, comps, "wo", fa_wo_tone::create(ssb)); - } else { - for (int i = 1; i <= m_wo; ++i) { - key = "wo" + std::to_string(i); - add_comp(keys, comps, key, fa_wo_tone::create(ssb)); - } - } - // Done! - return comp_data; - } - - void fourier_analysis::if_key_not_available_throw(const str_t& key) const - { - if (is_reserved(key)) { - throw runtime_error("key '" + key + "' is reserved"); - } else if (is_comp(key) || is_var(key)) { - throw runtime_error("key '" + key + "' already exists"); - } else if (!is_valid(key)) { - throw runtime_error("key '" + key + "' is invalid"); - } - } - -} // namespace genalyzer_impl - Non-Public +const str_t fourier_analysis::key_pattern = "[[:alpha:]][[:alnum:]_]*"; + +const str_t fourier_analysis::wo_pattern = "^wo[1-9]?$"; + +const std::set fourier_analysis::reserved_keys = { + "co", // comp/var : converter offset + "dc", // comp : DC + "fbin", // var : frequency bin size + "fdata", // var : data rate + "fs", // var : sample rate + "fshift" // var : shift frequency +}; + +const str_vector fourier_analysis::reserved_patterns = { + fourier_analysis::wo_pattern +}; + +const str_t fourier_analysis::flat_key_coupler = ":"; + +void fourier_analysis::add_comp(str_vector &keys, comp_map &comps, + const str_t &k, comp_ptr c) { + if (comps.find(k) != comps.end()) { + throw runtime_error("fourier_analysis::add_comp : key '" + k + + "' already exists"); + } + keys.push_back(k); + comps.insert({ k, std::move(c) }); +} + +int fourier_analysis::limit_ssb(int ssb, int lower_limit) { + lower_limit = (lower_limit < 0) ? -1 : std::get<0>(mmd_ssb); + return std::clamp(ssb, lower_limit, std::get<1>(mmd_ssb)); +} + +fourier_analysis::comp_data_t fourier_analysis::generate_comps(bool cplx) const { + bool find_fi = en_fund_images && cplx; + bool find_qe = en_quad_errors && cplx; + comp_data_t comp_data; + str_vector &keys = std::get<0>(comp_data); + comp_map &comps = std::get<1>(comp_data); + std::set &ilos_clk_keys = std::get<2>(comp_data); + str_t key = ""; + int ssb = 0; + // DC and Converter Offset Components + ssb = (m_ssb_dc < 0) ? m_ssb_def : m_ssb_dc; + add_comp(keys, comps, "dc", fa_dc::create(ssb)); + if (en_conv_offset) { + add_comp(keys, comps, "co", + fa_fixed_tone::create(FACompTag::UserDist, "0", ssb)); + } + // Interleaving Offset and Clock Components + std::set ilos_clk_terms; + std::set ilv_terms; + for (int x : m_ilv) { + for (int i = 1; i <= x / 2; ++i) { + ilv_terms.emplace(i, x, "fs"); + ilos_clk_terms.emplace(i, x, "fs"); + } + } + std::set clk_terms; + for (int x : m_clk) { + for (int i = 1; i <= x / 2; ++i) { + if (1 == std::gcd(i, x)) { + clk_terms.emplace(i, x, "fs"); + ilos_clk_terms.emplace(i, x, "fs"); + } + } + } + for (const fraction &f : ilos_clk_terms) { + key = f.term; + if (ilv_terms.end() != ilv_terms.find(f)) { + bool is_also_clk = clk_terms.end() != clk_terms.find(f); + add_comp(keys, comps, key, + fa_fixed_tone::create(FACompTag::ILOS, key, + m_ssb_def)); + if (is_also_clk) { + ilos_clk_keys.insert(key); + } + if (cplx && "fs/2" != key) { + key.insert(0, 1, '-'); + add_comp(keys, comps, key, + fa_fixed_tone::create(FACompTag::ILOS, + key, m_ssb_def)); + if (is_also_clk) { + ilos_clk_keys.insert(key); + } + } + } else { + add_comp(keys, comps, key, + fa_fixed_tone::create(FACompTag::CLK, key, + m_ssb_def)); + if (cplx && "fs/2" != key) { + key.insert(0, 1, '-'); + add_comp(keys, comps, key, + fa_fixed_tone::create(FACompTag::CLK, + key, m_ssb_def)); + } + } + } + // User and Auto Components + str_vector fund_keys; + int def_sig_ssb = (m_ssb_sig < 0) ? m_ssb_def : m_ssb_sig; + for (const str_t &ukey : m_user_keys) { + const comp_ptr &comp = m_user_comps.at(ukey); + int def_user_ssb = (FACompTag::Signal == comp->tag) ? def_sig_ssb : m_ssb_def; + if (FACompType::FixedTone == comp->type) { + const auto &c = + static_cast(*comp); + ssb = (c.ssb < 0) ? def_user_ssb : c.ssb; + add_comp(keys, comps, ukey, + fa_fixed_tone::create(c.tag, c.freq, ssb)); + } else if (FACompType::MaxTone == comp->type) { + const auto &c = static_cast(*comp); + ssb = (c.ssb < 0) ? def_user_ssb : c.ssb; + add_comp(keys, comps, ukey, + fa_max_tone::create(c.tag, c.center, c.width, + ssb)); + } else { + throw runtime_error( + "fourier_analysis::generate_comps : unsupported component type"); + } + if (FACompTag::Signal != comp->tag) { + continue; + } + fund_keys.push_back(ukey); + ssb = m_ssb_def; + // Fundamental Image Component + if (find_fi) { + key = '-' + ukey; + add_comp(keys, comps, key, + fa_fixed_tone::create(FACompTag::HD, key, + ssb)); + } + // Harmonic Distortion Components + for (int i = 2; i <= m_hd; ++i) { + if (is_even(i)) { + // even order + key = std::to_string(i) + ukey; + add_comp(keys, comps, key, + fa_fixed_tone::create(FACompTag::HD, + key, ssb)); + if (cplx) { + key.insert(0, 1, '-'); + add_comp(keys, comps, key, + fa_fixed_tone::create( + FACompTag::HD, key, + ssb)); + } + } else { + // odd order + // real data: j = +i + // cplx data: j = -i for 3, 7, 11... + // j = +i for 5, 9, 13... + int j = (cplx && is_odd(i / 2)) ? -i : i; + key = std::to_string(j) + ukey; + add_comp(keys, comps, key, + fa_fixed_tone::create(FACompTag::HD, + key, ssb)); + if (find_qe) { + key = std::to_string(-j) + ukey; + add_comp(keys, comps, key, + fa_fixed_tone::create( + FACompTag::HD, key, + ssb)); + } + } + } + // Interleaving Gain and Timing Components + for (const fraction &f : ilv_terms) { + key = ukey + '+' + f.term; + add_comp(keys, comps, key, + fa_fixed_tone::create(FACompTag::ILGT, key, + ssb)); + if ("fs/2" != f.term) { + key = ukey + '-' + f.term; + add_comp(keys, comps, key, + fa_fixed_tone::create(FACompTag::ILGT, + key, ssb)); + } + if (find_qe) { + key = negate(ukey + '+' + f.term, true); + add_comp(keys, comps, key, + fa_fixed_tone::create(FACompTag::ILGT, + key, ssb)); + if ("fs/2" != f.term) { + key = negate(ukey + '-' + f.term, true); + add_comp(keys, comps, key, + fa_fixed_tone::create( + FACompTag::ILGT, key, + ssb)); + } + } + } + // Intermodulation Distorion Components + for (const str_t &ka : fund_keys) { + if (ka == ukey) { + continue; + } + const str_t &kb = ukey; + for (int order = 2; order <= m_imd; ++order) { + int group = is_even(order) ? 0 : 1; + int pp = 0; + int qq = 0; + str_t p = ""; + str_t q = ""; + for (; group <= order; group += 2) { + if (group < order) { + // form: p * kx MINUS q * ky + pp = (order + group) / 2; + qq = order - pp; + p = (1 == pp) ? "" : std::to_string(pp); + q = (1 == qq) ? "" : std::to_string(qq); + if (0 == group) { + key = p + kb + '-' + q + + ka; + add_comp( + keys, comps, + key, + fa_fixed_tone::create( + FACompTag:: + IMD, + key, + ssb)); + if (cplx) { + key = negate( + key, + true); + add_comp( + keys, + comps, + key, + fa_fixed_tone::create( + FACompTag:: + IMD, + key, + ssb)); + } + } else if (is_even(order)) { + // even order + key = p + ka + '-' + q + + kb; + add_comp( + keys, comps, + key, + fa_fixed_tone::create( + FACompTag:: + IMD, + key, + ssb)); + key = p + kb + '-' + q + + ka; + add_comp( + keys, comps, + key, + fa_fixed_tone::create( + FACompTag:: + IMD, + key, + ssb)); + if (cplx) { + key = negate( + p + ka + + '-' + + q + + kb, + true); + add_comp( + keys, + comps, + key, + fa_fixed_tone::create( + FACompTag:: + IMD, + key, + ssb)); + key = negate( + p + kb + + '-' + + q + + ka, + true); + add_comp( + keys, + comps, + key, + fa_fixed_tone::create( + FACompTag:: + IMD, + key, + ssb)); + } + } else { + // odd order + bool neg = + cplx && + is_odd(group / + 2); + key = negate( + p + ka + '-' + + q + kb, + neg); + add_comp( + keys, comps, + key, + fa_fixed_tone::create( + FACompTag:: + IMD, + key, + ssb)); + key = negate( + p + kb + '-' + + q + ka, + neg); + add_comp( + keys, comps, + key, + fa_fixed_tone::create( + FACompTag:: + IMD, + key, + ssb)); + if (cplx) { + key = negate( + p + ka + + '-' + + q + + kb, + !neg); + add_comp( + keys, + comps, + key, + fa_fixed_tone::create( + FACompTag:: + IMD, + key, + ssb)); + key = negate( + p + kb + + '-' + + q + + ka, + !neg); + add_comp( + keys, + comps, + key, + fa_fixed_tone::create( + FACompTag:: + IMD, + key, + ssb)); + } + } + } else { // group == order + // form: p * kx PLUS q * ky + if (is_even(order)) { + // even order + for (qq = 1; qq < group; + ++qq) { + pp = order - qq; + p = (1 == pp) ? "" : std::to_string(pp); + q = (1 == qq) ? "" : std::to_string(qq); + key = p + ka + + '+' + q + + kb; + add_comp( + keys, + comps, + key, + fa_fixed_tone::create( + FACompTag:: + IMD, + key, + ssb)); + } + if (cplx) { + for (pp = 1; + pp < group; + ++pp) { + qq = order - + pp; + p = (1 == + pp) + ? "" + : std::to_string( + pp); + q = (1 == + qq) + ? "" + : std::to_string( + qq); + key = negate( + p + ka + + '+' + + q + + kb, + true); + add_comp( + keys, + comps, + key, + fa_fixed_tone::create( + FACompTag:: + IMD, + key, + ssb)); + } + } + } else { + // odd order + bool neg = + cplx && + is_odd(group / + 2); + for (qq = 1; qq < group; + ++qq) { + pp = order - qq; + p = (1 == pp) ? "" : std::to_string(pp); + q = (1 == qq) ? "" : std::to_string(qq); + key = negate( + p + ka + + '+' + + q + + kb, + neg); + add_comp( + keys, + comps, + key, + fa_fixed_tone::create( + FACompTag:: + IMD, + key, + ssb)); + } + if (find_qe) { + for (pp = 1; + pp < group; + ++pp) { + qq = order - + pp; + p = (1 == + pp) + ? "" + : std::to_string( + pp); + q = (1 == + qq) + ? "" + : std::to_string( + qq); + key = negate( + p + ka + + '+' + + q + + kb, + !neg); + add_comp( + keys, + comps, + key, + fa_fixed_tone::create( + FACompTag:: + IMD, + key, + ssb)); + } + } + } + } + } + } + } + } + // WO Components + ssb = (m_ssb_wo < 0) ? m_ssb_def : m_ssb_wo; + if (1 == m_wo) { + add_comp(keys, comps, "wo", fa_wo_tone::create(ssb)); + } else { + for (int i = 1; i <= m_wo; ++i) { + key = "wo" + std::to_string(i); + add_comp(keys, comps, key, fa_wo_tone::create(ssb)); + } + } + // Done! + return comp_data; +} + +void fourier_analysis::if_key_not_available_throw(const str_t &key) const { + if (is_reserved(key)) { + throw runtime_error("key '" + key + "' is reserved"); + } else if (is_comp(key) || is_var(key)) { + throw runtime_error("key '" + key + "' already exists"); + } else if (!is_valid(key)) { + throw runtime_error("key '" + key + "' is invalid"); + } +} + +} // namespace genalyzer_impl namespace genalyzer_impl { // Analysis and related subroutines - namespace { - - using comp_index_mag_t = std::pair; - - enum class FAMask : int { - AB = 0x1000, // Analysis Band - Comp, // All components - WO, // Used to search for worst others - NAD, // Noise and distortion - THD, // Total harmonic distortion: HD + IMD - ILV, // Interleaving: ILOS + ILGT - Dist, // Total distortion: THD + UserDist [+ CLK] [+ ILV] - Noise // Total noise: NAD - Dist - }; - - real_t alias(real_t freq, real_t fs, bool fold) - { - freq -= std::floor(freq / fs) * fs; // freq in [0, fs) - return (fold && fs < 2 * freq) ? (fs - freq) : freq; - } - - bool check_args( - const real_t* msq_data, - const size_t msq_size, - const size_t nfft, - const cplx_t* fft_data, - const size_t fft_size - ) - { - check_array("", "mean-square magnitude array", msq_data, msq_size); - bool cplx = msq_size == nfft; - if (!cplx) { - if (msq_size != nfft / 2 + 1) { - throw runtime_error("check_args : data size error"); - } - } - if (fft_data) { - if (msq_size != fft_size) { - throw runtime_error("check_args : data size error"); - } - } - return cplx; - } - - fa_tone_results null_tone_results(FACompTag tag) - { - fa_tone_results results; - results.set(FAToneResult::Tag , static_cast(tag)); - results.set(FAToneResult::Freq , 0.0); - results.set(FAToneResult::FFinal , 0.0); - results.set(FAToneResult::FWAvg , 0.0); - results.set(FAToneResult::InBand , 0.0); - results.set(FAToneResult::I1 , -1.0); - results.set(FAToneResult::I2 , -1.0); - results.set(FAToneResult::NBins , 0.0); - results.set_mag(0.0); - return results; - } - - real_t fa_db10(real_t msq_num, real_t msq_den = 1.0) - { - if (msq_num <= 0.0 && msq_den <= 0.0) { - return 0.0; - } else if (msq_num <= 0.0) { - return k_abs_min_db; - } else if (msq_den <= 0.0) { - return k_abs_max_db; - } else { - return bounded_db10(msq_num / msq_den); - } - } - - real_t fa_phase( - const fa_tone_results& r, - const cplx_t* fft_data, - bool cplx, - real_t fdata, - real_t fshift - ) - { - real_t phase = 0.0; - if (fft_data && 1 == r.get(FAToneResult::NBins)) { - diff_t index = static_cast(r.get(FAToneResult::I1)); - phase = std::arg(fft_data[index]); - if (!cplx) { - real_t f = r.get(FAToneResult::Freq) + fshift; - f -= std::floor(f / fdata) * fdata; // f in [0, fdata) - if (fdata <= 2 * f) { - phase *= -1.0; // invert phase if falias is in 2nd NZ - } - } - } - return phase; - } - - diff_p get_lrbins(size_t nfft, bool cplx, real_t cycles, int ssb) - { - // Find nearest half cycle: - real_t nearest_half_cycle = cycles; // initialize to exact cycles - bool on_half_cycle = false; // false: x.0, true: x.5 - if (0 < ssb) { // generate_comps() guarantees 0 <= ssb - nearest_half_cycle = std::round(nearest_half_cycle * 2.0); - on_half_cycle = is_odd(static_cast(nearest_half_cycle)); - nearest_half_cycle *= 0.5; // nearest half cycle (x.0 or x.5) - } else { - nearest_half_cycle = std::round(nearest_half_cycle); // nearest whole cycle (x.0) - } - // Re-alias for special cases - nearest_half_cycle = alias(nearest_half_cycle, static_cast(nfft), !cplx); - // Resolve SSB: - int min_ssb = std::get<0>(fourier_analysis::mmd_ssb); - int max_ssb = std::get<1>(fourier_analysis::mmd_ssb); - max_ssb = static_cast(std::min(nfft / 2, max_ssb)); - if (is_even(nfft) && !on_half_cycle) { // Example( NFFT=32, !on_half_cycle ): - max_ssb -= 1; // ssb=16 -> 1+2*16=33 bins - too many! - } // subtract 1: ssb=15 -> 1+2*15=31 bins - OK - ssb = std::clamp(ssb, min_ssb, max_ssb); - real_t half_width = static_cast(ssb); - if (on_half_cycle) { - half_width -= 0.5; - } - // Left and right bins: - diff_t lbin = static_cast(nearest_half_cycle - half_width); - diff_t rbin = static_cast(nearest_half_cycle + half_width); - return diff_p(lbin, rbin); - } - - bool has_tone_results(const fourier_analysis_component& c) - { - return (FACompType::DC == c.type) - || (FACompType::FixedTone == c.type) - || (FACompType::MaxTone == c.type) - || (FACompType::WOTone == c.type); - } - - fa_tone_results meas_dc( - const fa_dc& comp, - const real_t* msq_data, - const size_t msq_size, - const size_t nfft, - fourier_analysis::mask_map& masks - ) - { - const bool cplx = msq_size == nfft; - const diff_p lrbins = get_lrbins(nfft, cplx, 0.0, comp.ssb); - fourier_analysis_comp_mask m (cplx, msq_size); - m.set_range(lrbins.first, lrbins.second); - masks.at(to_int(FACompTag::DC)) = m; - masks.at(to_int(FAMask::Comp)) |= m; - size_t i1, i2, nbins; - std::tie(i1, i2, nbins) = m.get_indexes(); - real_t fwavg = 0.0; // FIXME: Real: 0.0 by definition; Cplx: calc - bool inband = masks.at(to_int(FAMask::AB)).overlaps(i1, i2); - real_t mag2 = m.sum(msq_data, msq_size); - fa_tone_results results; - results.set(FAToneResult::Tag , static_cast(FACompTag::DC)); - results.set(FAToneResult::Freq , 0.0); - results.set(FAToneResult::FFinal , 0.0); - results.set(FAToneResult::FWAvg , fwavg); - results.set(FAToneResult::I1 , static_cast(i1)); - results.set(FAToneResult::I2 , static_cast(i2)); - results.set(FAToneResult::NBins , static_cast(nbins)); - results.set(FAToneResult::InBand , inband ? 1.0 : 0.0); - results.set_mag(mag2); - return results; - } - - fa_tone_results meas_fixed_tone( - const str_t& key, - const fa_fixed_tone& comp, - const real_t* msq_data, - const size_t msq_size, - const size_t nfft, - fourier_analysis::mask_map& masks, - fourier_analysis::var_map& vars - ) - { - const bool cplx = msq_size == nfft; - const real_t fbin = vars.at("fbin"); - const real_t fdata = vars.at("fdata"); - const real_t fshift = vars.at("fshift"); - const real_t freq = expression(comp.freq).evaluate(vars); // "actual" frequency - const real_t ffinal = alias(freq + fshift, fdata, !cplx); // freq after translation and aliasing - const diff_p lrbins = get_lrbins(nfft, cplx, (ffinal / fbin), comp.ssb); - vars[key] = freq; - fourier_analysis_comp_mask m (cplx, msq_size); - m.set_range(lrbins.first, lrbins.second); - masks.at(to_int(comp.tag)) |= m; - masks.at(to_int(FAMask::Comp)) |= m; - size_t i1, i2, nbins; - std::tie(i1, i2, nbins) = m.get_indexes(); - real_t fwavg = 0.0; // FIXME - bool inband = masks.at(to_int(FAMask::AB)).overlaps(i1, i2); - real_t mag2 = m.sum(msq_data, msq_size); - fa_tone_results results; - results.set(FAToneResult::Tag , static_cast(comp.tag)); - results.set(FAToneResult::Freq , freq); - results.set(FAToneResult::FFinal , ffinal); - results.set(FAToneResult::FWAvg , fwavg); - results.set(FAToneResult::InBand , inband ? 1.0 : 0.0); - results.set(FAToneResult::I1 , static_cast(i1)); - results.set(FAToneResult::I2 , static_cast(i2)); - results.set(FAToneResult::NBins , static_cast(nbins)); - results.set_mag(mag2); - return results; - } - - // May implement search band in future. Note: search band != analysis band. - fa_tone_results meas_max_tone( - const str_t& key, - const fa_max_tone& comp, - const real_t* msq_data, - const size_t msq_size, - const size_t nfft, - fourier_analysis::mask_map& masks, - fourier_analysis::var_map& vars - ) - { - fourier_analysis_comp_mask search_mask = masks.at(to_int(FAMask::AB)); - fourier_analysis_comp_mask& comp_mask = masks.at(to_int(FAMask::Comp)); - search_mask.unset_ranges(comp_mask); - diff_t max_index, lower, upper; - std::tie(max_index, lower, upper) = search_mask.find_max_index(msq_data, msq_size); - if (max_index < 0) { - return null_tone_results(comp.tag); - } - const bool cplx = msq_size == nfft; - const real_t fbin = vars.at("fbin"); - const real_t fshift = vars.at("fshift"); - const real_t ffinal = max_index * fbin; - const real_t freq = ffinal - fshift; // this is a best guess - diff_p lrbins = get_lrbins(nfft, cplx, static_cast(max_index), comp.ssb); - // Unlike FixedTone, MaxTone stops when it runs into another tone. Since DC is always - // found and is always at bin 0, we never have to worry about MaxTone wrapping. - lrbins.first = std::max(lower, lrbins.first); - lrbins.second = std::min(lrbins.second, upper); - fourier_analysis_comp_mask m (cplx, msq_size); - m.set_range(lrbins.first, lrbins.second); - comp_mask |= m; // add this range to component mask - masks.at(to_int(comp.tag)) |= m; // add this range to tag mask - size_t i1, i2, nbins; - std::tie(i1, i2, nbins) = m.get_indexes(); - real_t fwavg = 0.0; // FIXME - bool inband = masks.at(to_int(FAMask::AB)).overlaps(i1, i2); - real_t mag2 = m.sum(msq_data, msq_size); - vars[key] = freq; // should probably use fwavg (once implemented) - fa_tone_results results; - results.set(FAToneResult::Tag , static_cast(comp.tag)); - results.set(FAToneResult::Freq , freq); - results.set(FAToneResult::FFinal , ffinal); - results.set(FAToneResult::FWAvg , fwavg); - results.set(FAToneResult::InBand , inband ? 1.0 : 0.0); - results.set(FAToneResult::I1 , static_cast(i1)); - results.set(FAToneResult::I2 , static_cast(i2)); - results.set(FAToneResult::NBins , static_cast(nbins)); - results.set_mag(mag2); - return results; - } - - fa_tone_results meas_wo_tone( - const fa_wo_tone& comp, - const real_t* msq_data, - const size_t msq_size, - const size_t nfft, - const real_t fbin, - const real_t fshift, - fourier_analysis::mask_map& masks - ) - { - fourier_analysis_comp_mask& wo_mask = masks.at(to_int(FAMask::WO)); - fourier_analysis_comp_mask& comp_mask = masks.at(to_int(FAMask::Comp)); - diff_t max_index, lower, upper; - std::tie(max_index, lower, upper) = wo_mask.find_max_index(msq_data, msq_size); - if (max_index < 0) { - return null_tone_results(comp.tag); - } - const bool cplx = msq_size == nfft; - const real_t ffinal = max_index * fbin; - const real_t freq = ffinal - fshift; // best guess - diff_p lrbins = get_lrbins(nfft, cplx, static_cast(max_index), comp.ssb); - // Unlike FixedTone, MaxTone stops when it runs into another tone. Since DC is always - // found and is always at bin 0, we never have to worry about MaxTone wrapping. - lrbins.first = std::max(lower, lrbins.first); - lrbins.second = std::min(lrbins.second, upper); - fourier_analysis_comp_mask m (cplx, msq_size); - m.set_range(lrbins.first, lrbins.second); - comp_mask |= m; // add this range to component mask - wo_mask.unset_ranges(m); // remove this range from WO search mask - size_t i1, i2, nbins; - std::tie(i1, i2, nbins) = m.get_indexes(); - real_t fwavg = 0.0; // FIXME - real_t mag2 = m.sum(msq_data, msq_size); - fa_tone_results results; - results.set(FAToneResult::Tag , static_cast(comp.tag)); - results.set(FAToneResult::Freq , freq); - results.set(FAToneResult::FFinal , ffinal); - results.set(FAToneResult::FWAvg , fwavg); - results.set(FAToneResult::InBand , 1.0); // by definition - results.set(FAToneResult::I1 , static_cast(i1)); - results.set(FAToneResult::I2 , static_cast(i2)); - results.set(FAToneResult::NBins , static_cast(nbins)); - results.set_mag(mag2); - return results; - } - - void update_maxspur( - size_t key_index, - const fa_tone_results& results, - bool dc_as_dist, - const fourier_analysis::mask_map& masks, - comp_index_mag_t& maxspur_im - ) - { - // A tone is a candidate for maxspur if: - // 1. it is in-band and non-Signal (these are assumed) - // 2. it is not DC, unless DC is treated as distortion (dc_as_dist is true) - // 3. it does not overlap any Signal tones (this needs explanation) - if (0.0 != results.get(FAToneResult::FFinal) || dc_as_dist) { - const fourier_analysis_comp_mask& sig_mask = masks.at(to_int(FACompTag::Signal)); - if (!sig_mask.overlaps(results.i1, results.i2)) { - real_t mag2 = results.get(FAToneResult::Mag); - mag2 *= mag2; - if (maxspur_im.first < 0 || maxspur_im.second < mag2) { - maxspur_im.first = static_cast(key_index); - maxspur_im.second = mag2; - } - } - } - } - - void tone_updates( - const str_t& key, - size_t key_index, - FACompTag tag, - const fa_tone_results& results, - bool dc_as_dist, - fourier_analysis::mask_map& masks, - const std::set& ilos_clk_keys, - comp_index_mag_t& carrier_im, - comp_index_mag_t& maxspur_im - ) - { - if (ilos_clk_keys.find(key) != ilos_clk_keys.end()) { - masks.at(to_int(FACompTag::CLK)).set_range(results.i1, results.i2); - } - if (results.inband) { - if (FACompTag::Signal == tag) { - real_t mag2 = results.get(FAToneResult::Mag); - mag2 *= mag2; - if (carrier_im.first < 0 || mag2 < carrier_im.second) { - carrier_im.first = static_cast(key_index); - carrier_im.second = mag2; - } - } else { - update_maxspur(key_index, results, dc_as_dist, masks, maxspur_im); - } - } - } - - } // namespace anonymous - - fourier_analysis::mask_map fourier_analysis::initialize_masks(bool cplx, size_t size) - { - mask_map masks { - {to_int(FAMask::AB) , fourier_analysis_comp_mask(cplx, size)}, - {to_int(FAMask::Comp) , fourier_analysis_comp_mask(cplx, size)}, - {to_int(FAMask::WO) , fourier_analysis_comp_mask(cplx, size)}, - {to_int(FAMask::NAD) , fourier_analysis_comp_mask(cplx, size)}, - {to_int(FAMask::THD) , fourier_analysis_comp_mask(cplx, size)}, - {to_int(FAMask::ILV) , fourier_analysis_comp_mask(cplx, size)}, - {to_int(FAMask::Dist) , fourier_analysis_comp_mask(cplx, size)}, - {to_int(FAMask::Noise) , fourier_analysis_comp_mask(cplx, size)} - }; - for (const std::pair& kv : fa_comp_tag_map) { - masks.emplace(kv.first, fourier_analysis_comp_mask(cplx, size)); - } - return masks; - } - - fourier_analysis_results fourier_analysis::analyze_impl( - const real_t* msq_data, - const size_t msq_size, - const size_t nfft, - FreqAxisType axis_type, - const cplx_t* fft_data, - const size_t fft_size - ) const - { - // - // Setup - // - const bool cplx = check_args(msq_data, msq_size, nfft, fft_data, fft_size); - mask_map masks = initialize_masks(cplx, msq_size); - var_map vars = initialize_vars(nfft); - const real_t fbin = vars.at("fbin"); - const real_t fdata = vars.at("fdata"); - const real_t fsample = vars.at("fs"); - const real_t fshift = vars.at("fshift"); - fourier_analysis_results results; - // - // Analysis Band - // - setup_analysis_band(cplx, masks.at(to_int(FAMask::AB)), vars); - // - // Component Generation - // CLK and ILOS components may overlap. Since the ILOS tag has higher priority, - // generate_comps() creates a dedicated list of CLK keys. - // - comp_data_t comp_data = generate_comps(cplx); - const str_vector& keys = std::get<0>(comp_data); - const comp_map& comps = std::get<1>(comp_data); - const std::set& ilos_clk_keys = std::get<2>(comp_data); - // - // Main Component Loop - // - comp_index_mag_t carrier_im {-1, 0.0}; - comp_index_mag_t maxspur_im {-1, 0.0}; - size_t key_index = 0; - for (; key_index < keys.size(); ++key_index) { - const str_t& key = keys[key_index]; - const fourier_analysis_component& comp = *comps.at(key); - switch (comp.type) - { - case FACompType::DC : { - auto& c = static_cast(comp); - fa_tone_results r = meas_dc(c, msq_data, msq_size, nfft, masks); - if (r.inband && dc_as_dist) { - update_maxspur(key_index, r, dc_as_dist, masks, maxspur_im); - } - results.add_tone(key, std::move(r)); - break; - } case FACompType::FixedTone : { - auto& c = static_cast(comp); - fa_tone_results r = meas_fixed_tone(key, c, msq_data, msq_size, nfft, masks, vars); - tone_updates(key, key_index, comp.tag, r, dc_as_dist, masks, ilos_clk_keys, - carrier_im, maxspur_im); - results.add_tone(key, std::move(r)); - break; - } case FACompType::MaxTone : { - auto& c = static_cast(comp); - fa_tone_results r = meas_max_tone(key, c, msq_data, msq_size, nfft, masks, vars); - tone_updates(key, key_index, comp.tag, r, dc_as_dist, masks, ilos_clk_keys, - carrier_im, maxspur_im); - results.add_tone(key, std::move(r)); - break; - } default : - break; - } - if (FACompType::WOTone == comp.type) { - break; - } - } - // - // Worst Others - // WOs are handled separately in order to guarantee max to min order - // - std::multimap wo_mag_map; // maps WO magnitude to WO key - std::map wo_res_map; // maps WO key to WO results - fourier_analysis_comp_mask& wo_mask = masks.at(to_int(FAMask::WO)); - wo_mask = masks.at(to_int(FAMask::AB)); // Initialize WO mask with AB mask - wo_mask.unset_ranges(masks.at(to_int(FAMask::Comp))); // Then remove all components already found - const size_t first_wo_index = key_index; - for (; key_index < keys.size(); ++key_index) { - const str_t& key = keys[key_index]; - auto& c = static_cast(*comps.at(key)); - fa_tone_results r = meas_wo_tone(c, msq_data, msq_size, nfft, fbin, fshift, masks); - wo_mag_map.insert({r.get(FAToneResult::Mag), key}); - wo_res_map[key] = std::move(r); - } - // WOs are found. Now add to results in order from max to min. Update MaxSpur. - int wo_num = 0; - for (auto iter = wo_mag_map.crbegin(); iter != wo_mag_map.crend(); ++iter) { - const str_t& key = iter->second; - str_t new_key = "wo"; - if (1 < m_wo) { - new_key += std::to_string(++wo_num); - } - if (1 == m_wo || 1 == wo_num) { - update_maxspur(first_wo_index, wo_res_map.at(key), dc_as_dist, masks, maxspur_im); - } - results.add_tone(new_key, std::move(wo_res_map.at(key))); - } - // - // Second pass for dBc, phase, and phase_c. - // If there are no in-band Signal components, there is no Carrier. - // - real_t carrier_phase = 0.0; - if (0 < carrier_im.first) { - str_t carrier_key = keys[carrier_im.first]; - fa_tone_results& carrier_results = results.tone_results.at(carrier_key); - carrier_phase = fa_phase(carrier_results, fft_data, cplx, fdata, fshift); - } - for (size_t i = 0; i < keys.size(); ++i) { - const str_t& key = keys[i]; - if (has_tone_results(*comps.at(key))) { - fa_tone_results& r = results.tone_results.at(key); - real_t mag = r.get(FAToneResult::Mag); - real_t phase = fa_phase(r, fft_data, cplx, fdata, fshift); - r.set(FAToneResult::OrderIndex, static_cast(i)); - r.set(FAToneResult::Mag_dBc, fa_db10(mag * mag, carrier_im.second)); - r.set(FAToneResult::Phase, phase); - r.set(FAToneResult::Phase_c, phase - carrier_phase); - } - } - // - // ffinal adjustment (only for complex analysis) - // - if (cplx && FreqAxisType::DcCenter == axis_type) { - for (std::pair& kv : results.tone_results) { - double& ffinal = kv.second.results[FAToneResult::FFinal]; - if (fdata <= 2 * ffinal) { - ffinal -= fdata; - } - } - } - // - // Components finished, now the rest of the results - // - finalize_masks(masks); - std::tuple ab_info = masks.at(to_int(FAMask::AB)).get_indexes(); - real_t ab_nbins = static_cast(std::get<2>(ab_info)); - real_t ab_width = cplx ? ab_nbins * fbin : std::fmin(fdata / 2, ab_nbins * fbin); - real_t nad_ss = masks.at(to_int(FAMask::NAD)).sum(msq_data, msq_size); - real_t noise_ss = masks.at(to_int(FAMask::Noise)).sum(msq_data, msq_size); - real_t noise_nbins = masks.at(to_int(FAMask::Noise)).count_r(); - real_t signal_ss = masks.at(to_int(FACompTag::Signal)).sum(msq_data, msq_size); - results.set(FAResult::AnalysisType , static_cast(AnalysisType::Fourier)); - results.set(FAResult::SignalType , cplx ? 1.0 : 0.0); - results.set(FAResult::NFFT , static_cast(nfft)); - results.set(FAResult::DataSize , static_cast(msq_size)); - results.set(FAResult::FBin , fbin); - results.set(FAResult::FData , fdata); - results.set(FAResult::FSample , fsample); - results.set(FAResult::FShift , fshift); - results.set(FAResult::FSNR , fa_db10(1.0, noise_ss)); - results.set(FAResult::SNR , fa_db10(signal_ss, noise_ss)); - results.set(FAResult::SINAD , fa_db10(signal_ss, nad_ss)); - results.set(FAResult::SFDR , fa_db10(carrier_im.second, maxspur_im.second)); - results.set(FAResult::ABN , fa_db10(noise_ss / std::fmax(1.0, noise_nbins))); // avoid div by 0 - results.set(FAResult::NSD , fa_db10(noise_ss / ab_width)); - results.set(FAResult::CarrierIndex , static_cast(carrier_im.first)); - results.set(FAResult::MaxSpurIndex , static_cast(maxspur_im.first)); - results.set(FAResult::AB_Width , ab_width); - results.set(FAResult::AB_I1 , static_cast(std::get<0>(ab_info))); - results.set(FAResult::AB_I2 , static_cast(std::get<1>(ab_info))); - results.set(FAResult::AB_NBins , ab_nbins); - results.set(FAResult::AB_RSS , masks.at(to_int(FAMask::AB)).root_sum(msq_data, msq_size)); - results.set(FAResult::Signal_NBins , masks.at(to_int(FACompTag::Signal)).count_r()); - results.set(FAResult::Signal_RSS , std::sqrt(signal_ss)); - results.set(FAResult::CLK_NBins , masks.at(to_int(FACompTag::CLK)).count_r()); - results.set(FAResult::CLK_RSS , masks.at(to_int(FACompTag::CLK)).root_sum(msq_data, msq_size)); - results.set(FAResult::HD_NBins , masks.at(to_int(FACompTag::HD)).count_r()); - results.set(FAResult::HD_RSS , masks.at(to_int(FACompTag::HD)).root_sum(msq_data, msq_size)); - results.set(FAResult::ILOS_NBins , masks.at(to_int(FACompTag::ILOS)).count_r()); - results.set(FAResult::ILOS_RSS , masks.at(to_int(FACompTag::ILOS)).root_sum(msq_data, msq_size)); - results.set(FAResult::ILGT_NBins , masks.at(to_int(FACompTag::ILGT)).count_r()); - results.set(FAResult::ILGT_RSS , masks.at(to_int(FACompTag::ILGT)).root_sum(msq_data, msq_size)); - results.set(FAResult::IMD_NBins , masks.at(to_int(FACompTag::IMD)).count_r()); - results.set(FAResult::IMD_RSS , masks.at(to_int(FACompTag::IMD)).root_sum(msq_data, msq_size)); - results.set(FAResult::UserDist_NBins , masks.at(to_int(FACompTag::UserDist)).count_r()); - results.set(FAResult::UserDist_RSS , masks.at(to_int(FACompTag::UserDist)).root_sum(msq_data, msq_size)); - results.set(FAResult::THD_NBins , masks.at(to_int(FAMask::THD)).count_r()); - results.set(FAResult::THD_RSS , masks.at(to_int(FAMask::THD)).root_sum(msq_data, msq_size)); - results.set(FAResult::ILV_NBins , masks.at(to_int(FAMask::ILV)).count_r()); - results.set(FAResult::ILV_RSS , masks.at(to_int(FAMask::ILV)).root_sum(msq_data, msq_size)); - results.set(FAResult::Dist_NBins , masks.at(to_int(FAMask::Dist)).count_r()); - results.set(FAResult::Dist_RSS , masks.at(to_int(FAMask::Dist)).root_sum(msq_data, msq_size)); - results.set(FAResult::Noise_NBins , masks.at(to_int(FAMask::Noise)).count_r()); - results.set(FAResult::Noise_RSS , std::sqrt(noise_ss)); - results.set(FAResult::NAD_NBins , masks.at(to_int(FAMask::NAD)).count_r()); - results.set(FAResult::NAD_RSS , std::sqrt(nad_ss)); - return results; - } - - // This function needs a detailed explanation. Don't edit this function unless you know what - // you are doing! Even the author wasn't quite sure what he was doing :) - void fourier_analysis::finalize_masks(mask_map& masks) const - { - const fourier_analysis_comp_mask& ab_mask = masks.at(to_int(FAMask::AB)); - // Signal Mask: remove out-of-band Signals - fourier_analysis_comp_mask& sig_mask = masks.at(to_int(FACompTag::Signal)); - sig_mask &= ab_mask; - // Noise-And-Distortion Mask: start with AnalysisBand, remove DC and Signals - fourier_analysis_comp_mask& nad_mask = masks.at(to_int(FAMask::NAD)); - nad_mask = ab_mask; - if (!dc_as_dist) { // Do not unset DC ranges if DC is treated as distortion - nad_mask.unset_ranges(masks.at(to_int(FACompTag::DC))); - } - nad_mask.unset_ranges(sig_mask); - // Tag Masks: remove Signals and out-of-band components; by virtue of the NAD mask, also - // remove DC if it is not treated as distortion - for (const std::pair& kv : fa_comp_tag_map) { - if (to_int(FACompTag::Signal) != kv.first) { // Don't touch the Signal mask! - masks.at(kv.first) &= nad_mask; - } - } - // THD - masks.at(to_int(FAMask::THD)) = masks.at(to_int(FACompTag::HD)); - masks.at(to_int(FAMask::THD)) |= masks.at(to_int(FACompTag::IMD)); - // Interleaving - masks.at(to_int(FAMask::ILV)) = masks.at(to_int(FACompTag::ILOS)); - masks.at(to_int(FAMask::ILV)) |= masks.at(to_int(FACompTag::ILGT)); - // Total Distortion - masks.at(to_int(FAMask::Dist)) = masks.at(to_int(FAMask::THD)); - masks.at(to_int(FAMask::Dist)) |= masks.at(to_int(FACompTag::UserDist)); - if (dc_as_dist) { - masks.at(to_int(FAMask::Dist)) |= masks.at(to_int(FACompTag::DC)); - } - if (!clk_as_noise) { - masks.at(to_int(FAMask::Dist)) |= masks.at(to_int(FACompTag::CLK)); - } - if (!ilv_as_noise) { - masks.at(to_int(FAMask::Dist)) |= masks.at(to_int(FAMask::ILV)); - } - // Noise - masks.at(to_int(FAMask::Noise)) = nad_mask; - masks.at(to_int(FAMask::Noise)).unset_ranges(masks.at(to_int(FAMask::Dist))); - } - - fourier_analysis::var_map fourier_analysis::initialize_vars(size_t nfft) const - { - var_map vars (m_user_vars); - real_t fsample = expression(m_fsample).evaluate(vars); - assert_gt0("", "fs", fsample); - vars["fs"] = fsample; - real_t fdata = expression(m_fdata).evaluate(vars); - assert_gt0("", "fdata", fdata); - real_t fbin = fdata / static_cast(nfft); - vars["fdata"] = fdata; - vars["fbin"] = fbin; - real_t fshift = expression(m_fshift).evaluate(vars); - vars["fshift"] = fshift; - return vars; - } - - void fourier_analysis::setup_analysis_band( - bool cplx, fourier_analysis_comp_mask& mask, var_map& vars) const - { - real_t center = expression(m_ab_center).evaluate(vars); - real_t width = expression(m_ab_width).evaluate(vars); - const real_t fbin = vars.at("fbin"); - const real_t fdata = vars.at("fdata"); - width = std::clamp(width, fbin, fdata); // [ fbin, fdata ] - width = std::round(width / fbin); // [ 1, nfft ] - if (mask.size() == static_cast(width)) { - mask.set_all(); - return; - } - center = alias(center, fdata, !cplx); - center = std::round(2.0 * center / fbin) / 2.0; // nearest half cycle - center = alias(center, fdata, !cplx); - diff_t lbin = static_cast(std::ceil( center - width / 2)); - diff_t rbin = static_cast(std::floor(center + width / 2)); - mask.set_range(lbin, rbin); - } - -} // namespace genalyzer_impl - Non-Public +namespace { + +using comp_index_mag_t = std::pair; + +enum class FAMask : int { + AB = 0x1000, // Analysis Band + Comp, // All components + WO, // Used to search for worst others + NAD, // Noise and distortion + THD, // Total harmonic distortion: HD + IMD + ILV, // Interleaving: ILOS + ILGT + Dist, // Total distortion: THD + UserDist [+ CLK] [+ ILV] + Noise // Total noise: NAD - Dist +}; + +real_t alias(real_t freq, real_t fs, bool fold) { + freq -= std::floor(freq / fs) * fs; // freq in [0, fs) + return (fold && fs < 2 * freq) ? (fs - freq) : freq; +} + +bool check_args(const real_t *msq_data, const size_t msq_size, + const size_t nfft, const cplx_t *fft_data, + const size_t fft_size) { + check_array("", "mean-square magnitude array", msq_data, msq_size); + bool cplx = msq_size == nfft; + if (!cplx) { + if (msq_size != nfft / 2 + 1) { + throw runtime_error("check_args : data size error"); + } + } + if (fft_data) { + if (msq_size != fft_size) { + throw runtime_error("check_args : data size error"); + } + } + return cplx; +} + +fa_tone_results null_tone_results(FACompTag tag) { + fa_tone_results results; + results.set(FAToneResult::Tag, static_cast(tag)); + results.set(FAToneResult::Freq, 0.0); + results.set(FAToneResult::FFinal, 0.0); + results.set(FAToneResult::FWAvg, 0.0); + results.set(FAToneResult::InBand, 0.0); + results.set(FAToneResult::I1, -1.0); + results.set(FAToneResult::I2, -1.0); + results.set(FAToneResult::NBins, 0.0); + results.set_mag(0.0); + return results; +} + +real_t fa_db10(real_t msq_num, real_t msq_den = 1.0) { + if (msq_num <= 0.0 && msq_den <= 0.0) { + return 0.0; + } else if (msq_num <= 0.0) { + return k_abs_min_db; + } else if (msq_den <= 0.0) { + return k_abs_max_db; + } else { + return bounded_db10(msq_num / msq_den); + } +} + +real_t fa_phase(const fa_tone_results &r, const cplx_t *fft_data, bool cplx, + real_t fdata, real_t fshift) { + real_t phase = 0.0; + if (fft_data && 1 == r.get(FAToneResult::NBins)) { + diff_t index = static_cast(r.get(FAToneResult::I1)); + phase = std::arg(fft_data[index]); + if (!cplx) { + real_t f = r.get(FAToneResult::Freq) + fshift; + f -= std::floor(f / fdata) * fdata; // f in [0, fdata) + if (fdata <= 2 * f) { + phase *= + -1.0; // invert phase if falias is in 2nd NZ + } + } + } + return phase; +} + +diff_p get_lrbins(size_t nfft, bool cplx, real_t cycles, int ssb) { + // Find nearest half cycle: + real_t nearest_half_cycle = cycles; // initialize to exact cycles + bool on_half_cycle = false; // false: x.0, true: x.5 + if (0 < ssb) { // generate_comps() guarantees 0 <= ssb + nearest_half_cycle = std::round(nearest_half_cycle * 2.0); + on_half_cycle = is_odd(static_cast(nearest_half_cycle)); + nearest_half_cycle *= 0.5; // nearest half cycle (x.0 or x.5) + } else { + nearest_half_cycle = std::round( + nearest_half_cycle); // nearest whole cycle (x.0) + } + // Re-alias for special cases + nearest_half_cycle = + alias(nearest_half_cycle, static_cast(nfft), !cplx); + // Resolve SSB: + int min_ssb = std::get<0>(fourier_analysis::mmd_ssb); + int max_ssb = std::get<1>(fourier_analysis::mmd_ssb); + max_ssb = static_cast(std::min(nfft / 2, max_ssb)); + if (is_even(nfft) && + !on_half_cycle) { // Example( NFFT=32, !on_half_cycle ): + max_ssb -= + 1; // ssb=16 -> 1+2*16=33 bins - too many! + } // subtract 1: ssb=15 -> 1+2*15=31 bins - OK + ssb = std::clamp(ssb, min_ssb, max_ssb); + real_t half_width = static_cast(ssb); + if (on_half_cycle) { + half_width -= 0.5; + } + // Left and right bins: + diff_t lbin = static_cast(nearest_half_cycle - half_width); + diff_t rbin = static_cast(nearest_half_cycle + half_width); + return diff_p(lbin, rbin); +} + +bool has_tone_results(const fourier_analysis_component &c) { + return (FACompType::DC == c.type) || + (FACompType::FixedTone == c.type) || + (FACompType::MaxTone == c.type) || + (FACompType::WOTone == c.type); +} + +fa_tone_results meas_dc(const fa_dc &comp, const real_t *msq_data, + const size_t msq_size, const size_t nfft, + fourier_analysis::mask_map &masks) { + const bool cplx = msq_size == nfft; + const diff_p lrbins = get_lrbins(nfft, cplx, 0.0, comp.ssb); + fourier_analysis_comp_mask m(cplx, msq_size); + m.set_range(lrbins.first, lrbins.second); + masks.at(to_int(FACompTag::DC)) = m; + masks.at(to_int(FAMask::Comp)) |= m; + size_t i1, i2, nbins; + std::tie(i1, i2, nbins) = m.get_indexes(); + real_t fwavg = 0.0; // FIXME: Real: 0.0 by definition; Cplx: calc + bool inband = masks.at(to_int(FAMask::AB)).overlaps(i1, i2); + real_t mag2 = m.sum(msq_data, msq_size); + fa_tone_results results; + results.set(FAToneResult::Tag, static_cast(FACompTag::DC)); + results.set(FAToneResult::Freq, 0.0); + results.set(FAToneResult::FFinal, 0.0); + results.set(FAToneResult::FWAvg, fwavg); + results.set(FAToneResult::I1, static_cast(i1)); + results.set(FAToneResult::I2, static_cast(i2)); + results.set(FAToneResult::NBins, static_cast(nbins)); + results.set(FAToneResult::InBand, inband ? 1.0 : 0.0); + results.set_mag(mag2); + return results; +} + +fa_tone_results meas_fixed_tone(const str_t &key, const fa_fixed_tone &comp, + const real_t *msq_data, const size_t msq_size, + const size_t nfft, + fourier_analysis::mask_map &masks, + fourier_analysis::var_map &vars) { + const bool cplx = msq_size == nfft; + const real_t fbin = vars.at("fbin"); + const real_t fdata = vars.at("fdata"); + const real_t fshift = vars.at("fshift"); + const real_t freq = + expression(comp.freq).evaluate(vars); // "actual" frequency + const real_t ffinal = + alias(freq + fshift, fdata, + !cplx); // freq after translation and aliasing + const diff_p lrbins = get_lrbins(nfft, cplx, (ffinal / fbin), comp.ssb); + vars[key] = freq; + fourier_analysis_comp_mask m(cplx, msq_size); + m.set_range(lrbins.first, lrbins.second); + masks.at(to_int(comp.tag)) |= m; + masks.at(to_int(FAMask::Comp)) |= m; + size_t i1, i2, nbins; + std::tie(i1, i2, nbins) = m.get_indexes(); + real_t fwavg = 0.0; // FIXME + bool inband = masks.at(to_int(FAMask::AB)).overlaps(i1, i2); + real_t mag2 = m.sum(msq_data, msq_size); + fa_tone_results results; + results.set(FAToneResult::Tag, static_cast(comp.tag)); + results.set(FAToneResult::Freq, freq); + results.set(FAToneResult::FFinal, ffinal); + results.set(FAToneResult::FWAvg, fwavg); + results.set(FAToneResult::InBand, inband ? 1.0 : 0.0); + results.set(FAToneResult::I1, static_cast(i1)); + results.set(FAToneResult::I2, static_cast(i2)); + results.set(FAToneResult::NBins, static_cast(nbins)); + results.set_mag(mag2); + return results; +} + +// May implement search band in future. Note: search band != analysis band. +fa_tone_results meas_max_tone(const str_t &key, const fa_max_tone &comp, + const real_t *msq_data, const size_t msq_size, + const size_t nfft, + fourier_analysis::mask_map &masks, + fourier_analysis::var_map &vars) { + fourier_analysis_comp_mask search_mask = masks.at(to_int(FAMask::AB)); + fourier_analysis_comp_mask &comp_mask = masks.at(to_int(FAMask::Comp)); + search_mask.unset_ranges(comp_mask); + diff_t max_index, lower, upper; + std::tie(max_index, lower, upper) = + search_mask.find_max_index(msq_data, msq_size); + if (max_index < 0) { + return null_tone_results(comp.tag); + } + const bool cplx = msq_size == nfft; + const real_t fbin = vars.at("fbin"); + const real_t fshift = vars.at("fshift"); + const real_t ffinal = max_index * fbin; + const real_t freq = ffinal - fshift; // this is a best guess + diff_p lrbins = get_lrbins(nfft, cplx, static_cast(max_index), + comp.ssb); + // Unlike FixedTone, MaxTone stops when it runs into another tone. Since DC + // is always found and is always at bin 0, we never have to worry about + // MaxTone wrapping. + lrbins.first = std::max(lower, lrbins.first); + lrbins.second = std::min(lrbins.second, upper); + fourier_analysis_comp_mask m(cplx, msq_size); + m.set_range(lrbins.first, lrbins.second); + comp_mask |= m; // add this range to component mask + masks.at(to_int(comp.tag)) |= m; // add this range to tag mask + size_t i1, i2, nbins; + std::tie(i1, i2, nbins) = m.get_indexes(); + real_t fwavg = 0.0; // FIXME + bool inband = masks.at(to_int(FAMask::AB)).overlaps(i1, i2); + real_t mag2 = m.sum(msq_data, msq_size); + vars[key] = freq; // should probably use fwavg (once implemented) + fa_tone_results results; + results.set(FAToneResult::Tag, static_cast(comp.tag)); + results.set(FAToneResult::Freq, freq); + results.set(FAToneResult::FFinal, ffinal); + results.set(FAToneResult::FWAvg, fwavg); + results.set(FAToneResult::InBand, inband ? 1.0 : 0.0); + results.set(FAToneResult::I1, static_cast(i1)); + results.set(FAToneResult::I2, static_cast(i2)); + results.set(FAToneResult::NBins, static_cast(nbins)); + results.set_mag(mag2); + return results; +} + +fa_tone_results meas_wo_tone(const fa_wo_tone &comp, const real_t *msq_data, + const size_t msq_size, const size_t nfft, + const real_t fbin, const real_t fshift, + fourier_analysis::mask_map &masks) { + fourier_analysis_comp_mask &wo_mask = masks.at(to_int(FAMask::WO)); + fourier_analysis_comp_mask &comp_mask = masks.at(to_int(FAMask::Comp)); + diff_t max_index, lower, upper; + std::tie(max_index, lower, upper) = + wo_mask.find_max_index(msq_data, msq_size); + if (max_index < 0) { + return null_tone_results(comp.tag); + } + const bool cplx = msq_size == nfft; + const real_t ffinal = max_index * fbin; + const real_t freq = ffinal - fshift; // best guess + diff_p lrbins = get_lrbins(nfft, cplx, static_cast(max_index), + comp.ssb); + // Unlike FixedTone, MaxTone stops when it runs into another tone. Since DC + // is always found and is always at bin 0, we never have to worry about + // MaxTone wrapping. + lrbins.first = std::max(lower, lrbins.first); + lrbins.second = std::min(lrbins.second, upper); + fourier_analysis_comp_mask m(cplx, msq_size); + m.set_range(lrbins.first, lrbins.second); + comp_mask |= m; // add this range to component mask + wo_mask.unset_ranges(m); // remove this range from WO search mask + size_t i1, i2, nbins; + std::tie(i1, i2, nbins) = m.get_indexes(); + real_t fwavg = 0.0; // FIXME + real_t mag2 = m.sum(msq_data, msq_size); + fa_tone_results results; + results.set(FAToneResult::Tag, static_cast(comp.tag)); + results.set(FAToneResult::Freq, freq); + results.set(FAToneResult::FFinal, ffinal); + results.set(FAToneResult::FWAvg, fwavg); + results.set(FAToneResult::InBand, 1.0); // by definition + results.set(FAToneResult::I1, static_cast(i1)); + results.set(FAToneResult::I2, static_cast(i2)); + results.set(FAToneResult::NBins, static_cast(nbins)); + results.set_mag(mag2); + return results; +} + +void update_maxspur(size_t key_index, const fa_tone_results &results, + bool dc_as_dist, const fourier_analysis::mask_map &masks, + comp_index_mag_t &maxspur_im) { + // A tone is a candidate for maxspur if: + // 1. it is in-band and non-Signal (these are assumed) + // 2. it is not DC, unless DC is treated as distortion (dc_as_dist is + // true) + // 3. it does not overlap any Signal tones (this needs explanation) + if (0.0 != results.get(FAToneResult::FFinal) || dc_as_dist) { + const fourier_analysis_comp_mask &sig_mask = + masks.at(to_int(FACompTag::Signal)); + if (!sig_mask.overlaps(results.i1, results.i2)) { + real_t mag2 = results.get(FAToneResult::Mag); + mag2 *= mag2; + if (maxspur_im.first < 0 || maxspur_im.second < mag2) { + maxspur_im.first = + static_cast(key_index); + maxspur_im.second = mag2; + } + } + } +} + +void tone_updates(const str_t &key, size_t key_index, FACompTag tag, + const fa_tone_results &results, bool dc_as_dist, + fourier_analysis::mask_map &masks, + const std::set &ilos_clk_keys, + comp_index_mag_t &carrier_im, comp_index_mag_t &maxspur_im) { + if (ilos_clk_keys.find(key) != ilos_clk_keys.end()) { + masks.at(to_int(FACompTag::CLK)) + .set_range(results.i1, results.i2); + } + if (results.inband) { + if (FACompTag::Signal == tag) { + real_t mag2 = results.get(FAToneResult::Mag); + mag2 *= mag2; + if (carrier_im.first < 0 || mag2 < carrier_im.second) { + carrier_im.first = + static_cast(key_index); + carrier_im.second = mag2; + } + } else { + update_maxspur(key_index, results, dc_as_dist, masks, + maxspur_im); + } + } +} + +} // namespace + +fourier_analysis::mask_map fourier_analysis::initialize_masks(bool cplx, + size_t size) { + mask_map masks{ + { to_int(FAMask::AB), fourier_analysis_comp_mask(cplx, size) }, + { to_int(FAMask::Comp), + fourier_analysis_comp_mask(cplx, size) }, + { to_int(FAMask::WO), fourier_analysis_comp_mask(cplx, size) }, + { to_int(FAMask::NAD), fourier_analysis_comp_mask(cplx, size) }, + { to_int(FAMask::THD), fourier_analysis_comp_mask(cplx, size) }, + { to_int(FAMask::ILV), fourier_analysis_comp_mask(cplx, size) }, + { to_int(FAMask::Dist), + fourier_analysis_comp_mask(cplx, size) }, + { to_int(FAMask::Noise), + fourier_analysis_comp_mask(cplx, size) } + }; + for (const std::pair &kv : fa_comp_tag_map) { + masks.emplace(kv.first, fourier_analysis_comp_mask(cplx, size)); + } + return masks; +} + +fourier_analysis_results +fourier_analysis::analyze_impl(const real_t *msq_data, const size_t msq_size, + const size_t nfft, FreqAxisType axis_type, + const cplx_t *fft_data, + const size_t fft_size) const { + // + // Setup + // + const bool cplx = + check_args(msq_data, msq_size, nfft, fft_data, fft_size); + mask_map masks = initialize_masks(cplx, msq_size); + var_map vars = initialize_vars(nfft); + const real_t fbin = vars.at("fbin"); + const real_t fdata = vars.at("fdata"); + const real_t fsample = vars.at("fs"); + const real_t fshift = vars.at("fshift"); + fourier_analysis_results results; + // + // Analysis Band + // + setup_analysis_band(cplx, masks.at(to_int(FAMask::AB)), vars); + // + // Component Generation + // CLK and ILOS components may overlap. Since the ILOS tag has higher + // priority, generate_comps() creates a dedicated list of CLK keys. + // + comp_data_t comp_data = generate_comps(cplx); + const str_vector &keys = std::get<0>(comp_data); + const comp_map &comps = std::get<1>(comp_data); + const std::set &ilos_clk_keys = std::get<2>(comp_data); + // + // Main Component Loop + // + comp_index_mag_t carrier_im{ -1, 0.0 }; + comp_index_mag_t maxspur_im{ -1, 0.0 }; + size_t key_index = 0; + for (; key_index < keys.size(); ++key_index) { + const str_t &key = keys[key_index]; + const fourier_analysis_component &comp = *comps.at(key); + switch (comp.type) { + case FACompType::DC: { + auto &c = static_cast(comp); + fa_tone_results r = + meas_dc(c, msq_data, msq_size, nfft, masks); + if (r.inband && dc_as_dist) { + update_maxspur(key_index, r, dc_as_dist, masks, + maxspur_im); + } + results.add_tone(key, std::move(r)); + break; + } + case FACompType::FixedTone: { + auto &c = static_cast(comp); + fa_tone_results r = meas_fixed_tone( + key, c, msq_data, msq_size, nfft, masks, vars); + tone_updates(key, key_index, comp.tag, r, dc_as_dist, + masks, ilos_clk_keys, carrier_im, + maxspur_im); + results.add_tone(key, std::move(r)); + break; + } + case FACompType::MaxTone: { + auto &c = static_cast(comp); + fa_tone_results r = meas_max_tone( + key, c, msq_data, msq_size, nfft, masks, vars); + tone_updates(key, key_index, comp.tag, r, dc_as_dist, + masks, ilos_clk_keys, carrier_im, + maxspur_im); + results.add_tone(key, std::move(r)); + break; + } + default: + break; + } + if (FACompType::WOTone == comp.type) { + break; + } + } + // + // Worst Others + // WOs are handled separately in order to guarantee max to min order + // + std::multimap wo_mag_map; // maps WO magnitude to WO key + std::map wo_res_map; // maps WO key to WO results + fourier_analysis_comp_mask &wo_mask = masks.at(to_int(FAMask::WO)); + wo_mask = + masks.at(to_int(FAMask::AB)); // Initialize WO mask with AB mask + wo_mask.unset_ranges(masks.at(to_int( + FAMask::Comp))); // Then remove all components already found + const size_t first_wo_index = key_index; + for (; key_index < keys.size(); ++key_index) { + const str_t &key = keys[key_index]; + auto &c = static_cast(*comps.at(key)); + fa_tone_results r = meas_wo_tone(c, msq_data, msq_size, nfft, + fbin, fshift, masks); + wo_mag_map.insert({ r.get(FAToneResult::Mag), key }); + wo_res_map[key] = std::move(r); + } + // WOs are found. Now add to results in order from max to min. Update + // MaxSpur. + int wo_num = 0; + for (auto iter = wo_mag_map.crbegin(); iter != wo_mag_map.crend(); + ++iter) { + const str_t &key = iter->second; + str_t new_key = "wo"; + if (1 < m_wo) { + new_key += std::to_string(++wo_num); + } + if (1 == m_wo || 1 == wo_num) { + update_maxspur(first_wo_index, wo_res_map.at(key), + dc_as_dist, masks, maxspur_im); + } + results.add_tone(new_key, std::move(wo_res_map.at(key))); + } + // + // Second pass for dBc, phase, and phase_c. + // If there are no in-band Signal components, there is no Carrier. + // + real_t carrier_phase = 0.0; + if (0 < carrier_im.first) { + str_t carrier_key = keys[carrier_im.first]; + fa_tone_results &carrier_results = + results.tone_results.at(carrier_key); + carrier_phase = fa_phase(carrier_results, fft_data, cplx, fdata, + fshift); + } + for (size_t i = 0; i < keys.size(); ++i) { + const str_t &key = keys[i]; + if (has_tone_results(*comps.at(key))) { + fa_tone_results &r = results.tone_results.at(key); + real_t mag = r.get(FAToneResult::Mag); + real_t phase = + fa_phase(r, fft_data, cplx, fdata, fshift); + r.set(FAToneResult::OrderIndex, static_cast(i)); + r.set(FAToneResult::Mag_dBc, + fa_db10(mag * mag, carrier_im.second)); + r.set(FAToneResult::Phase, phase); + r.set(FAToneResult::Phase_c, phase - carrier_phase); + } + } + // + // ffinal adjustment (only for complex analysis) + // + if (cplx && FreqAxisType::DcCenter == axis_type) { + for (std::pair &kv : + results.tone_results) { + double &ffinal = + kv.second.results[FAToneResult::FFinal]; + if (fdata <= 2 * ffinal) { + ffinal -= fdata; + } + } + } + // + // Components finished, now the rest of the results + // + finalize_masks(masks); + std::tuple ab_info = + masks.at(to_int(FAMask::AB)).get_indexes(); + real_t ab_nbins = static_cast(std::get<2>(ab_info)); + real_t ab_width = cplx ? ab_nbins * fbin : std::fmin(fdata / 2, ab_nbins * fbin); + real_t nad_ss = masks.at(to_int(FAMask::NAD)).sum(msq_data, msq_size); + real_t noise_ss = + masks.at(to_int(FAMask::Noise)).sum(msq_data, msq_size); + real_t noise_nbins = masks.at(to_int(FAMask::Noise)).count_r(); + real_t signal_ss = + masks.at(to_int(FACompTag::Signal)).sum(msq_data, msq_size); + results.set(FAResult::AnalysisType, + static_cast(AnalysisType::Fourier)); + results.set(FAResult::SignalType, cplx ? 1.0 : 0.0); + results.set(FAResult::NFFT, static_cast(nfft)); + results.set(FAResult::DataSize, static_cast(msq_size)); + results.set(FAResult::FBin, fbin); + results.set(FAResult::FData, fdata); + results.set(FAResult::FSample, fsample); + results.set(FAResult::FShift, fshift); + results.set(FAResult::FSNR, fa_db10(1.0, noise_ss)); + results.set(FAResult::SNR, fa_db10(signal_ss, noise_ss)); + results.set(FAResult::SINAD, fa_db10(signal_ss, nad_ss)); + results.set(FAResult::SFDR, + fa_db10(carrier_im.second, maxspur_im.second)); + results.set(FAResult::ABN, + fa_db10(noise_ss / + std::fmax(1.0, noise_nbins))); // avoid div by 0 + results.set(FAResult::NSD, fa_db10(noise_ss / ab_width)); + results.set(FAResult::CarrierIndex, + static_cast(carrier_im.first)); + results.set(FAResult::MaxSpurIndex, + static_cast(maxspur_im.first)); + results.set(FAResult::AB_Width, ab_width); + results.set(FAResult::AB_I1, static_cast(std::get<0>(ab_info))); + results.set(FAResult::AB_I2, static_cast(std::get<1>(ab_info))); + results.set(FAResult::AB_NBins, ab_nbins); + results.set(FAResult::AB_RSS, + masks.at(to_int(FAMask::AB)).root_sum(msq_data, msq_size)); + results.set(FAResult::Signal_NBins, + masks.at(to_int(FACompTag::Signal)).count_r()); + results.set(FAResult::Signal_RSS, std::sqrt(signal_ss)); + results.set(FAResult::CLK_NBins, + masks.at(to_int(FACompTag::CLK)).count_r()); + results.set( + FAResult::CLK_RSS, + masks.at(to_int(FACompTag::CLK)).root_sum(msq_data, msq_size)); + results.set(FAResult::HD_NBins, + masks.at(to_int(FACompTag::HD)).count_r()); + results.set( + FAResult::HD_RSS, + masks.at(to_int(FACompTag::HD)).root_sum(msq_data, msq_size)); + results.set(FAResult::ILOS_NBins, + masks.at(to_int(FACompTag::ILOS)).count_r()); + results.set( + FAResult::ILOS_RSS, + masks.at(to_int(FACompTag::ILOS)).root_sum(msq_data, msq_size)); + results.set(FAResult::ILGT_NBins, + masks.at(to_int(FACompTag::ILGT)).count_r()); + results.set( + FAResult::ILGT_RSS, + masks.at(to_int(FACompTag::ILGT)).root_sum(msq_data, msq_size)); + results.set(FAResult::IMD_NBins, + masks.at(to_int(FACompTag::IMD)).count_r()); + results.set( + FAResult::IMD_RSS, + masks.at(to_int(FACompTag::IMD)).root_sum(msq_data, msq_size)); + results.set(FAResult::UserDist_NBins, + masks.at(to_int(FACompTag::UserDist)).count_r()); + results.set(FAResult::UserDist_RSS, + masks.at(to_int(FACompTag::UserDist)) + .root_sum(msq_data, msq_size)); + results.set(FAResult::THD_NBins, + masks.at(to_int(FAMask::THD)).count_r()); + results.set(FAResult::THD_RSS, + masks.at(to_int(FAMask::THD)).root_sum(msq_data, msq_size)); + results.set(FAResult::ILV_NBins, + masks.at(to_int(FAMask::ILV)).count_r()); + results.set(FAResult::ILV_RSS, + masks.at(to_int(FAMask::ILV)).root_sum(msq_data, msq_size)); + results.set(FAResult::Dist_NBins, + masks.at(to_int(FAMask::Dist)).count_r()); + results.set( + FAResult::Dist_RSS, + masks.at(to_int(FAMask::Dist)).root_sum(msq_data, msq_size)); + results.set(FAResult::Noise_NBins, + masks.at(to_int(FAMask::Noise)).count_r()); + results.set(FAResult::Noise_RSS, std::sqrt(noise_ss)); + results.set(FAResult::NAD_NBins, + masks.at(to_int(FAMask::NAD)).count_r()); + results.set(FAResult::NAD_RSS, std::sqrt(nad_ss)); + return results; +} + +// This function needs a detailed explanation. Don't edit this function unless +// you know what you are doing! Even the author wasn't quite sure what he was +// doing :) +void fourier_analysis::finalize_masks(mask_map &masks) const { + const fourier_analysis_comp_mask &ab_mask = + masks.at(to_int(FAMask::AB)); + // Signal Mask: remove out-of-band Signals + fourier_analysis_comp_mask &sig_mask = + masks.at(to_int(FACompTag::Signal)); + sig_mask &= ab_mask; + // Noise-And-Distortion Mask: start with AnalysisBand, remove DC and Signals + fourier_analysis_comp_mask &nad_mask = masks.at(to_int(FAMask::NAD)); + nad_mask = ab_mask; + if (!dc_as_dist) { // Do not unset DC ranges if DC is treated as distortion + nad_mask.unset_ranges(masks.at(to_int(FACompTag::DC))); + } + nad_mask.unset_ranges(sig_mask); + // Tag Masks: remove Signals and out-of-band components; by virtue of the NAD + // mask, also remove DC if it is not treated as distortion + for (const std::pair &kv : fa_comp_tag_map) { + if (to_int(FACompTag::Signal) != + kv.first) { // Don't touch the Signal mask! + masks.at(kv.first) &= nad_mask; + } + } + // THD + masks.at(to_int(FAMask::THD)) = masks.at(to_int(FACompTag::HD)); + masks.at(to_int(FAMask::THD)) |= masks.at(to_int(FACompTag::IMD)); + // Interleaving + masks.at(to_int(FAMask::ILV)) = masks.at(to_int(FACompTag::ILOS)); + masks.at(to_int(FAMask::ILV)) |= masks.at(to_int(FACompTag::ILGT)); + // Total Distortion + masks.at(to_int(FAMask::Dist)) = masks.at(to_int(FAMask::THD)); + masks.at(to_int(FAMask::Dist)) |= masks.at(to_int(FACompTag::UserDist)); + if (dc_as_dist) { + masks.at(to_int(FAMask::Dist)) |= + masks.at(to_int(FACompTag::DC)); + } + if (!clk_as_noise) { + masks.at(to_int(FAMask::Dist)) |= + masks.at(to_int(FACompTag::CLK)); + } + if (!ilv_as_noise) { + masks.at(to_int(FAMask::Dist)) |= masks.at(to_int(FAMask::ILV)); + } + // Noise + masks.at(to_int(FAMask::Noise)) = nad_mask; + masks.at(to_int(FAMask::Noise)) + .unset_ranges(masks.at(to_int(FAMask::Dist))); +} + +fourier_analysis::var_map fourier_analysis::initialize_vars(size_t nfft) const { + var_map vars(m_user_vars); + real_t fsample = expression(m_fsample).evaluate(vars); + assert_gt0("", "fs", fsample); + vars["fs"] = fsample; + real_t fdata = expression(m_fdata).evaluate(vars); + assert_gt0("", "fdata", fdata); + real_t fbin = fdata / static_cast(nfft); + vars["fdata"] = fdata; + vars["fbin"] = fbin; + real_t fshift = expression(m_fshift).evaluate(vars); + vars["fshift"] = fshift; + return vars; +} + +void fourier_analysis::setup_analysis_band(bool cplx, + fourier_analysis_comp_mask &mask, + var_map &vars) const { + real_t center = expression(m_ab_center).evaluate(vars); + real_t width = expression(m_ab_width).evaluate(vars); + const real_t fbin = vars.at("fbin"); + const real_t fdata = vars.at("fdata"); + width = std::clamp(width, fbin, fdata); // [ fbin, fdata ] + width = std::round(width / fbin); // [ 1, nfft ] + if (mask.size() == static_cast(width)) { + mask.set_all(); + return; + } + center = alias(center, fdata, !cplx); + center = std::round(2.0 * center / fbin) / 2.0; // nearest half cycle + center = alias(center, fdata, !cplx); + diff_t lbin = static_cast(std::ceil(center - width / 2)); + diff_t rbin = static_cast(std::floor(center + width / 2)); + mask.set_range(lbin, rbin); +} + +} // namespace genalyzer_impl diff --git a/src/fourier_analysis_comp_mask.cpp b/src/fourier_analysis_comp_mask.cpp index 6850dde..a66babc 100644 --- a/src/fourier_analysis_comp_mask.cpp +++ b/src/fourier_analysis_comp_mask.cpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #include "fourier_analysis_comp_mask.hpp" #include "exceptions.hpp" @@ -7,248 +10,248 @@ namespace genalyzer_impl { - fourier_analysis_comp_mask::fourier_analysis_comp_mask( - bool cplx, size_t array_size, const std::vector& init) - : m_mode {cplx ? Wrap : Stop}, - m_ufirst {0}, - m_ulast {array_size - 1}, - m_usize {array_size}, - m_first {0}, - m_last {static_cast(array_size - 1)}, - m_size {static_cast(array_size)}, - m_data (init) - { - if (!m_data.empty()) { - const char* msg = "fourier_analysis_comp_mask : invalid construction"; - if ( is_odd(m_data.size()) || (m_usize < m_data.back()) ) { - throw runtime_error(msg); - } - for (size_t i = 1; i < m_data.size(); ++i) { - if (m_data[i] <= m_data[i - 1]) { - throw runtime_error(msg); - } - } - } - } - - fourier_analysis_comp_mask& fourier_analysis_comp_mask::operator&=(fourier_analysis_comp_mask m) - { - if_not_compat_then_throw(m); - this->invert(); // !A - m.invert(); // !B - *this |= m; // !A + !B - this->invert(); // !(!A + !B) - return *this; // De Morgan: A * B = !(!A + !B) - } - - fourier_analysis_comp_mask& fourier_analysis_comp_mask::operator|=( - const fourier_analysis_comp_mask& m) - { - if_not_compat_then_throw(m); - for (size_t range = 0; range < m.num_ranges(); ++range) { - size_t i1 = m.m_data[range * 2]; - size_t i2 = m.m_data[range * 2 + 1]; - this->set_range_safe(i1, i2 - 1); // subtract 1 because i2 is 1-past! - } - return *this; - } - - size_t fourier_analysis_comp_mask::count() const - { - size_t count = 0; - for (size_t range = 0; range < num_ranges(); ++range) { - const size_t i1 = m_data[range * 2]; - const size_t i2 = m_data[range * 2 + 1]; - for (size_t i = i1; i < i2; ++i) { - ++count; - } - } - return count; - } - - std::tuple - fourier_analysis_comp_mask::find_max_index(const real_t* data, size_t size) const - { - if (m_usize != size) { - throw runtime_error("fourier_analysis_comp_mask::find_max_index : size error"); - } - real_t max_value = 0.0; - diff_t max_index = -1; - size_t max_range = 0; - for (size_t range = 0; range < num_ranges(); ++range) { - const size_t i1 = m_data[range * 2]; - const size_t i2 = m_data[range * 2 + 1]; - for (size_t i = i1; i < i2; ++i) { - if (max_value < data[i]) { - max_value = data[i]; - max_index = i; - max_range = range; - } - } - } - if (max_index < 0) { - return std::make_tuple(-1, -1, -1); - } else { - diff_t lower = static_cast(m_data[max_range * 2]); - diff_t upper = static_cast(m_data[max_range * 2 + 1]) - 1; - return std::make_tuple(max_index, lower, upper); - } - } - - std::tuple fourier_analysis_comp_mask::get_indexes() const - { - if (1 == num_ranges()) { - return std::make_tuple(m_data[0], m_data[1] - 1, m_data[1] - m_data[0]); - } else if (2 == num_ranges() && m_ufirst == m_data[0] && m_usize == m_data[3]) { - return std::make_tuple(m_data[2], m_data[1] - 1, m_data[1] + m_data[3] - m_data[2]); - } else { - throw runtime_error("fourier_analysis_comp_mask::get_indexes : invalid use"); - } - } - - void fourier_analysis_comp_mask::invert() - { - if (m_data.empty()) { - set_all(); - return; - } - if (m_ufirst == m_data.front()) { - m_data.erase(m_data.begin()); - } else { - m_data.insert(m_data.begin(), m_ufirst); - } - if (m_usize == m_data.back()) { - m_data.pop_back(); - } else { - m_data.push_back(m_usize); - } - } - - bool fourier_analysis_comp_mask::overlaps(size_t left, size_t right) const - { - size_t left_index = get_index(left); - size_t right_index = get_index(right); - if (is_odd(left_index) || is_odd(right_index)) { // if either are inside a range - return true; - } - return left_index != right_index; // true if left and right straddle one or more ranges - } - - void fourier_analysis_comp_mask::set_range(diff_t left, diff_t right) - { - if (right < left) { - throw runtime_error("fourier_analysis_comp_mask::set_range : right < left"); - } - size_t uleft = 0; - size_t uright = 0; - if (Stop == m_mode) { - uleft = static_cast(std::max(m_first, left)); - uright = static_cast(std::min(right, m_last)); - } else { - if (m_last < right - left) { - throw runtime_error("fourier_analysis_comp_mask::set_range : size < range"); - } - if (left < m_first) { - left += m_size; - if (left < m_first) { - throw runtime_error("fourier_analysis_comp_mask::set_range : left out of range"); - } - } - if (m_last < right) { - right -= m_size; - if (m_last < right) { - throw runtime_error("fourier_analysis_comp_mask::set_range : right out of range"); - } - } - uleft = static_cast(left); - uright = static_cast(right); - } - if (uright < uleft) { - set_range_safe(m_ufirst, uright); - set_range_safe(uleft, m_ulast); - } else { - set_range_safe(uleft, uright); - } - } - - real_t fourier_analysis_comp_mask::sum(const real_t* data, size_t size) const - { - if (m_usize != size) { - throw runtime_error("fourier_analysis_comp_mask::sum : size error"); - } - real_t mag = 0.0; - for (size_t range = 0; range < num_ranges(); ++range) { - const size_t i1 = m_data[range * 2]; - const size_t i2 = m_data[range * 2 + 1]; - for (size_t i = i1; i < i2; ++i) { - mag += data[i]; - } - } - return mag; - } - - void fourier_analysis_comp_mask::unset_ranges(const fourier_analysis_comp_mask& m) - { - if (&m == this) { - this->clear(); - return; - } - if_not_compat_then_throw(m); - this->invert(); - *this |= m; - this->invert(); - } - - size_t fourier_analysis_comp_mask::get_index(size_t value) const - { - size_t index = 0; - while (index < m_data.size()) { - if (value < m_data[index]) { - break; - } - ++index; - } - return index; - } - - void fourier_analysis_comp_mask::if_not_compat_then_throw(const fourier_analysis_comp_mask& m) - { - if ((m.m_mode != this->m_mode) || (m.m_size != this->m_size)) { - throw runtime_error("fourier_analysis_comp_mask : mask is incompatible"); - } - } - - void fourier_analysis_comp_mask::set_range_safe(size_t left, size_t right) - { - right += 1; // right is now 1-past - if (m_data.empty() || m_data.back() < left) { - m_data.push_back(left); - m_data.push_back(right); - return; - } - size_t left_index = get_index(left); - size_t right_index = get_index(right); - // left and left_index adjustments - if (is_even(left_index)) { // even: left is not in a range - // Explain this... - if (0 < left_index && left == m_data[left_index - 1]) { - left_index -= 2; - left = m_data[left_index]; - } - } else { // odd: left is in a range - // Explain this... - left_index -= 1; - left = m_data[left_index]; - } - // right and right_index adjustments - if (is_odd(right_index)) { // odd: right is in a range - // Explain this... - right = m_data[right_index]; - right_index += 1; - } - // Update m_data - m_data.erase(m_data.begin() + left_index, m_data.begin() + right_index); - m_data.insert(m_data.begin() + left_index, {left, right}); - } +fourier_analysis_comp_mask::fourier_analysis_comp_mask( + bool cplx, size_t array_size, const std::vector &init) : + m_mode{ cplx ? Wrap : Stop }, m_ufirst{ 0 }, m_ulast{ array_size - 1 }, m_usize{ array_size }, m_first{ 0 }, m_last{ static_cast(array_size - 1) }, m_size{ static_cast(array_size) }, m_data(init) { + if (!m_data.empty()) { + const char *msg = + "fourier_analysis_comp_mask : invalid construction"; + if (is_odd(m_data.size()) || (m_usize < m_data.back())) { + throw runtime_error(msg); + } + for (size_t i = 1; i < m_data.size(); ++i) { + if (m_data[i] <= m_data[i - 1]) { + throw runtime_error(msg); + } + } + } +} + +fourier_analysis_comp_mask & +fourier_analysis_comp_mask::operator&=(fourier_analysis_comp_mask m) { + if_not_compat_then_throw(m); + this->invert(); // !A + m.invert(); // !B + *this |= m; // !A + !B + this->invert(); // !(!A + !B) + return *this; // De Morgan: A * B = !(!A + !B) +} + +fourier_analysis_comp_mask & +fourier_analysis_comp_mask::operator|=(const fourier_analysis_comp_mask &m) { + if_not_compat_then_throw(m); + for (size_t range = 0; range < m.num_ranges(); ++range) { + size_t i1 = m.m_data[range * 2]; + size_t i2 = m.m_data[range * 2 + 1]; + this->set_range_safe( + i1, i2 - 1); // subtract 1 because i2 is 1-past! + } + return *this; +} + +size_t fourier_analysis_comp_mask::count() const { + size_t count = 0; + for (size_t range = 0; range < num_ranges(); ++range) { + const size_t i1 = m_data[range * 2]; + const size_t i2 = m_data[range * 2 + 1]; + for (size_t i = i1; i < i2; ++i) { + ++count; + } + } + return count; +} + +std::tuple +fourier_analysis_comp_mask::find_max_index(const real_t *data, + size_t size) const { + if (m_usize != size) { + throw runtime_error( + "fourier_analysis_comp_mask::find_max_index : size error"); + } + real_t max_value = 0.0; + diff_t max_index = -1; + size_t max_range = 0; + for (size_t range = 0; range < num_ranges(); ++range) { + const size_t i1 = m_data[range * 2]; + const size_t i2 = m_data[range * 2 + 1]; + for (size_t i = i1; i < i2; ++i) { + if (max_value < data[i]) { + max_value = data[i]; + max_index = i; + max_range = range; + } + } + } + if (max_index < 0) { + return std::make_tuple(-1, -1, -1); + } else { + diff_t lower = static_cast(m_data[max_range * 2]); + diff_t upper = + static_cast(m_data[max_range * 2 + 1]) - 1; + return std::make_tuple(max_index, lower, upper); + } +} + +std::tuple +fourier_analysis_comp_mask::get_indexes() const { + if (1 == num_ranges()) { + return std::make_tuple(m_data[0], m_data[1] - 1, + m_data[1] - m_data[0]); + } else if (2 == num_ranges() && m_ufirst == m_data[0] && + m_usize == m_data[3]) { + return std::make_tuple(m_data[2], m_data[1] - 1, + m_data[1] + m_data[3] - m_data[2]); + } else { + throw runtime_error( + "fourier_analysis_comp_mask::get_indexes : invalid use"); + } +} + +void fourier_analysis_comp_mask::invert() { + if (m_data.empty()) { + set_all(); + return; + } + if (m_ufirst == m_data.front()) { + m_data.erase(m_data.begin()); + } else { + m_data.insert(m_data.begin(), m_ufirst); + } + if (m_usize == m_data.back()) { + m_data.pop_back(); + } else { + m_data.push_back(m_usize); + } +} + +bool fourier_analysis_comp_mask::overlaps(size_t left, size_t right) const { + size_t left_index = get_index(left); + size_t right_index = get_index(right); + if (is_odd(left_index) || + is_odd(right_index)) { // if either are inside a range + return true; + } + return left_index != + right_index; // true if left and right straddle one or more ranges +} + +void fourier_analysis_comp_mask::set_range(diff_t left, diff_t right) { + if (right < left) { + throw runtime_error( + "fourier_analysis_comp_mask::set_range : right < left"); + } + size_t uleft = 0; + size_t uright = 0; + if (Stop == m_mode) { + uleft = static_cast(std::max(m_first, left)); + uright = static_cast(std::min(right, m_last)); + } else { + if (m_last < right - left) { + throw runtime_error( + "fourier_analysis_comp_mask::set_range : size < range"); + } + if (left < m_first) { + left += m_size; + if (left < m_first) { + throw runtime_error( + "fourier_analysis_comp_mask::set_range : left out of range"); + } + } + if (m_last < right) { + right -= m_size; + if (m_last < right) { + throw runtime_error( + "fourier_analysis_comp_mask::set_range : right out of range"); + } + } + uleft = static_cast(left); + uright = static_cast(right); + } + if (uright < uleft) { + set_range_safe(m_ufirst, uright); + set_range_safe(uleft, m_ulast); + } else { + set_range_safe(uleft, uright); + } +} + +real_t fourier_analysis_comp_mask::sum(const real_t *data, size_t size) const { + if (m_usize != size) { + throw runtime_error( + "fourier_analysis_comp_mask::sum : size error"); + } + real_t mag = 0.0; + for (size_t range = 0; range < num_ranges(); ++range) { + const size_t i1 = m_data[range * 2]; + const size_t i2 = m_data[range * 2 + 1]; + for (size_t i = i1; i < i2; ++i) { + mag += data[i]; + } + } + return mag; +} + +void fourier_analysis_comp_mask::unset_ranges( + const fourier_analysis_comp_mask &m) { + if (&m == this) { + this->clear(); + return; + } + if_not_compat_then_throw(m); + this->invert(); + *this |= m; + this->invert(); +} + +size_t fourier_analysis_comp_mask::get_index(size_t value) const { + size_t index = 0; + while (index < m_data.size()) { + if (value < m_data[index]) { + break; + } + ++index; + } + return index; +} + +void fourier_analysis_comp_mask::if_not_compat_then_throw( + const fourier_analysis_comp_mask &m) { + if ((m.m_mode != this->m_mode) || (m.m_size != this->m_size)) { + throw runtime_error( + "fourier_analysis_comp_mask : mask is incompatible"); + } +} + +void fourier_analysis_comp_mask::set_range_safe(size_t left, size_t right) { + right += 1; // right is now 1-past + if (m_data.empty() || m_data.back() < left) { + m_data.push_back(left); + m_data.push_back(right); + return; + } + size_t left_index = get_index(left); + size_t right_index = get_index(right); + // left and left_index adjustments + if (is_even(left_index)) { // even: left is not in a range + // Explain this... + if (0 < left_index && left == m_data[left_index - 1]) { + left_index -= 2; + left = m_data[left_index]; + } + } else { // odd: left is in a range + // Explain this... + left_index -= 1; + left = m_data[left_index]; + } + // right and right_index adjustments + if (is_odd(right_index)) { // odd: right is in a range + // Explain this... + right = m_data[right_index]; + right_index += 1; + } + // Update m_data + m_data.erase(m_data.begin() + left_index, m_data.begin() + right_index); + m_data.insert(m_data.begin() + left_index, { left, right }); +} } // namespace genalyzer_impl \ No newline at end of file diff --git a/src/fourier_transforms.cpp b/src/fourier_transforms.cpp index 7f8fc6b..5071f30 100644 --- a/src/fourier_transforms.cpp +++ b/src/fourier_transforms.cpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #include "fourier_transforms.hpp" #include "constants.hpp" @@ -13,1002 +16,920 @@ namespace genalyzer_impl { - namespace { // Window Function Constants - - const real_t blackman_harris_kx = 1.9688861870585801; - const real_t blackman_harris_k0 = 0.35875; - const real_t blackman_harris_k1 = -0.48829; - const real_t blackman_harris_k2 = 0.14128; - const real_t blackman_harris_k3 = -0.01168; - const real_t hann_kx = 1.6329922791756648; - const real_t hann_k0 = 0.5; - const real_t hann_k1 = -0.5; - - } // namespace anonymous - - namespace { // Window-Only Functions - - // For Complex FFT - void blackman_harris( - const real_t* i_data, - const real_t* q_data, - real_t* out_data, - size_t in_stride, - size_t navg, - size_t nfft - ) - { - const real_t scalar = blackman_harris_kx; - const real_t k1 = k_2pi / static_cast(nfft); - const real_t k2 = k1 * 2; - const real_t k3 = k1 * 3; - const size_t in_row_stride = nfft * in_stride; - const size_t out_row_stride = nfft * 2; - size_t i = 0; - real_t x = 0.0; - if (1 == navg) { - for (size_t j = 0; j < out_row_stride; j += 2) { - const real_t w = blackman_harris_k0 - + blackman_harris_k1 * std::cos(k1 * x) - + blackman_harris_k2 * std::cos(k2 * x) - + blackman_harris_k3 * std::cos(k3 * x); - out_data[j] = w * scalar * i_data[i]; - out_data[j+1] = w * scalar * q_data[i]; - i += in_stride; - x += 1.0; - } - } else if (2 == navg) { - const real_t* i2_data = i_data + in_row_stride; - const real_t* q2_data = q_data + in_row_stride; - real_t* out2_data = out_data + out_row_stride; - for (size_t j = 0; j < out_row_stride; j += 2) { - const real_t w = blackman_harris_k0 - + blackman_harris_k1 * std::cos(k1 * x) - + blackman_harris_k2 * std::cos(k2 * x) - + blackman_harris_k3 * std::cos(k3 * x); - out_data[j] = w * scalar * i_data[i]; - out_data[j+1] = w * scalar * q_data[i]; - out2_data[j] = w * scalar * i2_data[i]; - out2_data[j+1] = w * scalar * q2_data[i]; - i += in_stride; - x += 1.0; - } - } else { // 2 < navg - for (size_t j = 0; j < out_row_stride; j += 2) { - const real_t w = blackman_harris_k0 - + blackman_harris_k1 * std::cos(k1 * x) - + blackman_harris_k2 * std::cos(k2 * x) - + blackman_harris_k3 * std::cos(k3 * x); - const real_t* pi = i_data; - const real_t* pq = q_data; - real_t* po = out_data; - for (size_t k = 0; k < navg; ++k) { - po[j] = w * scalar * pi[i]; - po[j+1] = w * scalar * pq[i]; - pi += in_row_stride; - pq += in_row_stride; - po += out_row_stride; - } - i += in_stride; - x += 1.0; - } - } - } - - // For Real FFT - void blackman_harris( - const real_t* in_data, - real_t* out_data, - size_t navg, - size_t nfft, - RfftScale scale - ) - { - const real_t scalar = blackman_harris_kx * ((RfftScale::DbfsSin == scale) ? k_sqrt2 : 1.0); - const real_t k1 = k_2pi / static_cast(nfft); - const real_t k2 = k1 * 2; - const real_t k3 = k1 * 3; - const size_t out_stride = (nfft / 2 + 1) * 2; - real_t x = 0.0; - if (1 == navg) { - for (size_t i = 0; i < nfft; ++i) { - const real_t w = blackman_harris_k0 - + blackman_harris_k1 * std::cos(k1 * x) - + blackman_harris_k2 * std::cos(k2 * x) - + blackman_harris_k3 * std::cos(k3 * x); - out_data[i] = w * scalar * in_data[i]; - x += 1.0; - } - } else if (2 == navg) { - const real_t* in2_data = in_data + nfft; - real_t* out2_data = out_data + out_stride; - for (size_t i = 0; i < nfft; ++i) { - const real_t w = blackman_harris_k0 - + blackman_harris_k1 * std::cos(k1 * x) - + blackman_harris_k2 * std::cos(k2 * x) - + blackman_harris_k3 * std::cos(k3 * x); - out_data[i] = w * scalar * in_data[i]; - out2_data[i] = w * scalar * in2_data[i]; - x += 1.0; - } - } else { // 2 < navg - for (size_t i = 0; i < nfft; ++i) { - const real_t w = blackman_harris_k0 - + blackman_harris_k1 * std::cos(k1 * x) - + blackman_harris_k2 * std::cos(k2 * x) - + blackman_harris_k3 * std::cos(k3 * x); - const real_t* pi = in_data; - real_t* po = out_data; - for (size_t j = 0; j < navg; ++j) { - po[i] = w * scalar * pi[i]; - pi += nfft; - po += out_stride; - } - x += 1.0; - } - } - } - - // For Complex FFT - void hann( - const real_t* i_data, - const real_t* q_data, - real_t* out_data, - size_t in_stride, - size_t navg, - size_t nfft - ) - { - const real_t scalar = hann_kx; - const real_t k1 = k_2pi / static_cast(nfft); - const size_t in_row_stride = nfft * in_stride; - const size_t out_row_stride = nfft * 2; - size_t i = 0; - real_t x = 0.0; - if (1 == navg) { - for (size_t j = 0; j < out_row_stride; j += 2) { - const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); - out_data[j] = w * scalar * i_data[i]; - out_data[j+1] = w * scalar * q_data[i]; - i += in_stride; - x += 1.0; - } - } else if (2 == navg) { - const real_t* i2_data = i_data + nfft * in_stride; - const real_t* q2_data = q_data + nfft * in_stride; - real_t* out2_data = out_data + out_row_stride; - for (size_t j = 0; j < out_row_stride; j += 2) { - const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); - out_data[j] = w * scalar * i_data[i]; - out_data[j+1] = w * scalar * q_data[i]; - out2_data[j] = w * scalar * i2_data[i]; - out2_data[j+1] = w * scalar * q2_data[i]; - i += in_stride; - x += 1.0; - } - } else { // 2 < navg - for (size_t j = 0; j < out_row_stride; j += 2) { - const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); - const real_t* pi = i_data; - const real_t* pq = q_data; - real_t* po = out_data; - for (size_t k = 0; k < navg; ++k) { - po[j] = w * scalar * pi[i]; - po[j+1] = w * scalar * pq[i]; - pi += in_row_stride; - pq += in_row_stride; - po += out_row_stride; - } - i += in_stride; - x += 1.0; - } - } - } - - // For Real FFT - void hann( - const real_t* in_data, - real_t* out_data, - size_t navg, - size_t nfft, - RfftScale scale - ) - { - const real_t scalar = hann_kx * ((RfftScale::DbfsSin == scale) ? k_sqrt2 : 1.0); - const real_t k1 = k_2pi / static_cast(nfft); - const size_t out_stride = (nfft / 2 + 1) * 2; - real_t x = 0.0; - if (1 == navg) { - for (size_t i = 0; i < nfft; ++i) { - const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); - out_data[i] = w * scalar * in_data[i]; - x += 1.0; - } - } else if (2 == navg) { - const real_t* in2_data = in_data + nfft; - real_t* out2_data = out_data + out_stride; - for (size_t i = 0; i < nfft; ++i) { - const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); - out_data[i] = w * scalar * in_data[i]; - out2_data[i] = w * scalar * in2_data[i]; - x += 1.0; - } - } else { // 2 < navg - for (size_t i = 0; i < nfft; ++i) { - const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); - const real_t* pi = in_data; - real_t* po = out_data; - for (size_t j = 0; j < navg; ++j) { - po[i] = w * scalar * pi[i]; - pi += nfft; - po += out_stride; - } - x += 1.0; - } - } - } - - // For Complex FFT - void no_window( - const real_t* i_data, - const real_t* q_data, - real_t* out_data, - size_t in_stride, - size_t navg, - size_t nfft - ) - { - const size_t out_size = navg * nfft * 2; - size_t i = 0; - for (size_t j = 0; j < out_size; j += 2) { - out_data[j] = i_data[i]; - out_data[j+1] = q_data[i]; - i += in_stride; - } - } - - // For Real FFT - void no_window( - const real_t* in_data, - real_t* out_data, - size_t navg, - size_t nfft, - RfftScale scale - ) - { - const real_t scalar = (RfftScale::DbfsSin == scale) ? k_sqrt2 : 1.0; - const size_t out_stride = (nfft / 2 + 1) * 2; - for (size_t j = 0; j < navg; ++j) { - for (size_t i = 0; i < nfft; ++i) { - out_data[i] = scalar * in_data[i]; - } - in_data += nfft; - out_data += out_stride; - } - } - - } // namespace anonymous - - namespace { // Normalize-Window Functions - - // For Complex FFT - template - void norm_blackman_harris( - const T* i_data, - const T* q_data, - real_t* out_data, - size_t in_stride, - int n, - size_t navg, - size_t nfft, - CodeFormat format - ) - { - const real_t scalar = blackman_harris_kx * 2.0 / (1 << n); - const real_t offset = (CodeFormat::OffsetBinary == format) ? -blackman_harris_kx : 0.0; - const real_t k1 = k_2pi / static_cast(nfft); - const real_t k2 = k1 * 2; - const real_t k3 = k1 * 3; - const size_t in_row_stride = nfft * in_stride; - const size_t out_row_stride = nfft * 2; - size_t i = 0; - real_t x = 0.0; - if (1 == navg) { - for (size_t j = 0; j < out_row_stride; j += 2) { - const real_t w = blackman_harris_k0 - + blackman_harris_k1 * std::cos(k1 * x) - + blackman_harris_k2 * std::cos(k2 * x) - + blackman_harris_k3 * std::cos(k3 * x); - out_data[j] = w * std::fma(scalar, static_cast(i_data[i]), offset); - out_data[j+1] = w * std::fma(scalar, static_cast(q_data[i]), offset); - i += in_stride; - x += 1.0; - } - } else if (2 == navg) { - const T* i2_data = i_data + in_row_stride; - const T* q2_data = q_data + in_row_stride; - real_t* out2_data = out_data + out_row_stride; - for (size_t j = 0; j < out_row_stride; j += 2) { - const real_t w = blackman_harris_k0 - + blackman_harris_k1 * std::cos(k1 * x) - + blackman_harris_k2 * std::cos(k2 * x) - + blackman_harris_k3 * std::cos(k3 * x); - out_data[j] = w * std::fma(scalar, static_cast(i_data[i]), offset); - out_data[j+1] = w * std::fma(scalar, static_cast(q_data[i]), offset); - out2_data[j] = w * std::fma(scalar, static_cast(i2_data[i]), offset); - out2_data[j+1] = w * std::fma(scalar, static_cast(q2_data[i]), offset); - i += in_stride; - x += 1.0; - } - } else { // 2 < navg - for (size_t j = 0; j < out_row_stride; j += 2) { - const real_t w = blackman_harris_k0 - + blackman_harris_k1 * std::cos(k1 * x) - + blackman_harris_k2 * std::cos(k2 * x) - + blackman_harris_k3 * std::cos(k3 * x); - const T* pi = i_data; - const T* pq = q_data; - real_t* po = out_data; - for (size_t k = 0; k < navg; ++k) { - po[j] = w * std::fma(scalar, static_cast(pi[i]), offset); - po[j+1] = w * std::fma(scalar, static_cast(pq[i]), offset); - pi += in_row_stride; - pq += in_row_stride; - po += out_row_stride; - } - i += in_stride; - x += 1.0; - } - } - } - - // For Real FFT - template - void norm_blackman_harris( - const T* in_data, - real_t* out_data, - int n, - size_t navg, - size_t nfft, - CodeFormat format, - RfftScale scale - ) - { - real_t s = blackman_harris_kx * ((RfftScale::DbfsSin == scale) ? k_sqrt2 : 1.0); - const real_t scalar = s * 2.0 / (1 << n); - const real_t offset = (CodeFormat::OffsetBinary == format) ? -s : 0.0; - const real_t k1 = k_2pi / static_cast(nfft); - const real_t k2 = k1 * 2; - const real_t k3 = k1 * 3; - const size_t out_stride = (nfft / 2 + 1) * 2; - real_t x = 0.0; - if (1 == navg) { - for (size_t i = 0; i < nfft; ++i) { - const real_t w = blackman_harris_k0 - + blackman_harris_k1 * std::cos(k1 * x) - + blackman_harris_k2 * std::cos(k2 * x) - + blackman_harris_k3 * std::cos(k3 * x); - out_data[i] = w * std::fma(scalar, static_cast(in_data[i]), offset); - x += 1.0; - } - } else if (2 == navg) { - const T* in2_data = in_data + nfft; - real_t* out2_data = out_data + out_stride; - for (size_t i = 0; i < nfft; ++i) { - const real_t w = blackman_harris_k0 - + blackman_harris_k1 * std::cos(k1 * x) - + blackman_harris_k2 * std::cos(k2 * x) - + blackman_harris_k3 * std::cos(k3 * x); - out_data[i] = w * std::fma(scalar, static_cast(in_data[i]), offset); - out2_data[i] = w * std::fma(scalar, static_cast(in2_data[i]), offset); - x += 1.0; - } - } else { // 2 < navg - for (size_t i = 0; i < nfft; ++i) { - const real_t w = blackman_harris_k0 - + blackman_harris_k1 * std::cos(k1 * x) - + blackman_harris_k2 * std::cos(k2 * x) - + blackman_harris_k3 * std::cos(k3 * x); - const T* pi = in_data; - real_t* po = out_data; - for (size_t j = 0; j < navg; ++j) { - po[i] = w * std::fma(scalar, static_cast(pi[i]), offset); - pi += nfft; - po += out_stride; - } - x += 1.0; - } - } - } - - // For Complex FFT - template - void norm_hann( - const T* i_data, - const T* q_data, - real_t* out_data, - size_t in_stride, - int n, - size_t navg, - size_t nfft, - CodeFormat format - ) - { - const real_t scalar = hann_kx * 2.0 / (1 << n); - const real_t offset = (CodeFormat::OffsetBinary == format) ? -hann_kx : 0.0; - const real_t k1 = k_2pi / static_cast(nfft); - const size_t in_row_stride = nfft * in_stride; - const size_t out_row_stride = nfft * 2; - size_t i = 0; - real_t x = 0.0; - if (1 == navg) { - for (size_t j = 0; j < out_row_stride; j += 2) { - const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); - out_data[j] = w * std::fma(scalar, static_cast(i_data[i]), offset); - out_data[j+1] = w * std::fma(scalar, static_cast(q_data[i]), offset); - i += in_stride; - x += 1.0; - } - } else if (2 == navg) { - const T* i2_data = i_data + nfft * in_stride; - const T* q2_data = q_data + nfft * in_stride; - real_t* out2_data = out_data + out_row_stride; - for (size_t j = 0; j < out_row_stride; j += 2) { - const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); - out_data[j] = w * std::fma(scalar, static_cast(i_data[i]), offset); - out_data[j+1] = w * std::fma(scalar, static_cast(q_data[i]), offset); - out2_data[j] = w * std::fma(scalar, static_cast(i2_data[i]), offset); - out2_data[j+1] = w * std::fma(scalar, static_cast(q2_data[i]), offset); - i += in_stride; - x += 1.0; - } - } else { // 2 < navg - for (size_t j = 0; j < out_row_stride; j += 2) { - const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); - const T* pi = i_data; - const T* pq = q_data; - real_t* po = out_data; - for (size_t k = 0; k < navg; ++k) { - po[j] = w * std::fma(scalar, static_cast(pi[i]), offset); - po[j+1] = w * std::fma(scalar, static_cast(pq[i]), offset); - pi += in_row_stride; - pq += in_row_stride; - po += out_row_stride; - } - i += in_stride; - x += 1.0; - } - } - } - - // For Real FFT - template - void norm_hann( - const T* in_data, - real_t* out_data, - int n, - size_t navg, - size_t nfft, - CodeFormat format, - RfftScale scale - ) - { - real_t s = hann_kx * ((RfftScale::DbfsSin == scale) ? k_sqrt2 : 1.0); - const real_t scalar = s * 2.0 / (1 << n); - const real_t offset = (CodeFormat::OffsetBinary == format) ? -s : 0.0; - const real_t k1 = k_2pi / static_cast(nfft); - const size_t out_stride = (nfft / 2 + 1) * 2; - real_t x = 0.0; - if (1 == navg) { - for (size_t i = 0; i < nfft; ++i) { - const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); - out_data[i] = w * std::fma(scalar, static_cast(in_data[i]), offset); - x += 1.0; - } - } else if (2 == navg) { - const T* in2_data = in_data + nfft; - real_t* out2_data = out_data + out_stride; - for (size_t i = 0; i < nfft; ++i) { - const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); - out_data[i] = w * std::fma(scalar, static_cast(in_data[i]), offset); - out2_data[i] = w * std::fma(scalar, static_cast(in2_data[i]), offset); - x += 1.0; - } - } else { // 2 < navg - for (size_t i = 0; i < nfft; ++i) { - const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); - const T* pi = in_data; - real_t* po = out_data; - for (size_t j = 0; j < navg; ++j) { - po[i] = w * std::fma(scalar, static_cast(pi[i]), offset); - pi += nfft; - po += out_stride; - } - x += 1.0; - } - } - } - - // For Complex FFT - template - void norm_no_window( - const T* i_data, - const T* q_data, - real_t* out_data, - size_t in_stride, - int n, - size_t navg, - size_t nfft, - CodeFormat format - ) - { - const real_t scalar = 2.0 / (1 << n); - const real_t offset = (CodeFormat::OffsetBinary == format) ? -1.0 : 0.0; - const size_t out_size = navg * nfft * 2; - size_t i = 0; - for (size_t j = 0; j < out_size; j += 2) { - out_data[j] = std::fma(scalar, static_cast(i_data[i]), offset); - out_data[j+1] = std::fma(scalar, static_cast(q_data[i]), offset); - i += in_stride; - } - } - - // For Real FFT - template - void norm_no_window( - const T* in_data, - real_t* out_data, - int n, - size_t navg, - size_t nfft, - CodeFormat format, - RfftScale scale - ) - { - real_t s = (RfftScale::DbfsSin == scale) ? k_sqrt2 : 1.0; - const real_t scalar = s * 2.0 / (1 << n); - const real_t offset = (CodeFormat::OffsetBinary == format) ? -s : 0.0; - const size_t out_stride = (nfft / 2 + 1) * 2; - for (size_t j = 0; j < navg; ++j) { - for (size_t i = 0; i < nfft; ++i) { - out_data[i] = std::fma(scalar, static_cast(in_data[i]), offset); - } - in_data += nfft; - out_data += out_stride; - } - } - - } // namespace anonymous - - namespace { // FFTW Functions - - void exec_fftw(real_t* data, size_t navg, size_t nfft) - { - diff_t navg_ = static_cast(navg); - diff_t nfft_ = static_cast(nfft); - // FFT size: FFTW "rank" and "dims" - int rank = 1; - fftw_iodim64 dims {nfft_, 2, 2}; - // FFT averaging: FFTW "howmany_rank" and "howmany_dims" - int howmany_rank = 1; - fftw_iodim64 howmany_dims = {navg_, nfft_ * 2, nfft_ * 2}; - // FFTW plan setup and execution - fftw_plan plan = fftw_plan_guru64_split_dft( - rank, - &dims, - howmany_rank, - &howmany_dims, - data, // I input - data + 1, // Q input - data, // Re output - data + 1, // Im output - FFTW_ESTIMATE); - if (nullptr == plan) { - throw runtime_error("FFTW Plan is NULL"); - } - fftw_execute(plan); - fftw_destroy_plan(plan); - } - - void exec_rfftw(real_t* data, size_t navg, size_t nfft) - { - diff_t navg_ = static_cast(navg); - diff_t nfft_ = static_cast(nfft); - diff_t out_stride = nfft_ / 2 + 1; - // FFT size: FFTW "rank" and "dims" - int rank = 1; - fftw_iodim64 dims {nfft_, 1, 1}; - // FFT averaging: FFTW "howmany_rank" and "howmany_dims" - int howmany_rank = 1; - fftw_iodim64 howmany_dims {navg_, out_stride * 2, out_stride}; - // Plan setup and execution - fftw_complex* out_data = reinterpret_cast(data); - fftw_plan plan = fftw_plan_guru64_dft_r2c( - rank, - &dims, - howmany_rank, - &howmany_dims, - data, - out_data, - FFTW_ESTIMATE); - if (nullptr == plan) { - throw runtime_error("FFTW Plan is NULL"); - } - fftw_execute(plan); - fftw_destroy_plan(plan); - } - - } // namespace anonymous - - namespace { // Scaling and Averaging Functions - - void reduce_and_scale_fft(real_t* fftw_data, real_t* out_data, size_t navg, size_t nfft) - { - cplx_t* cfftw_data = reinterpret_cast(fftw_data); - cplx_t* cout_data = reinterpret_cast(out_data); - for (size_t i = 0; i < nfft; ++i) { - cout_data[i] = {std::norm(cfftw_data[i]), std::arg(cfftw_data[i])}; - } - for (size_t j = 1; j < navg; ++j) { - cfftw_data += nfft; - for (size_t i = 0; i < nfft; ++i) { - cout_data[i] += cplx_t(std::norm(cfftw_data[i]), std::arg(cfftw_data[i])); - } - } - const real_t avg_scalar = 1.0 / static_cast(navg); - const real_t fft_scalar = 1.0 / static_cast(nfft); - for (size_t i = 0; i < nfft; ++i) { - cplx_t& x = cout_data[i]; - x *= avg_scalar; - x = std::polar(std::sqrt(x.real()) * fft_scalar, x.imag()); - } - } - - void reduce_and_scale_rfft( - real_t* fftw_data, real_t* out_data, size_t navg, size_t nfft, RfftScale scale) - { - cplx_t* cfftw_data = reinterpret_cast(fftw_data); - cplx_t* cout_data = reinterpret_cast(out_data); - const size_t cout_size = nfft / 2 + 1; - for (size_t i = 0; i < cout_size; ++i) { - cout_data[i] = {std::norm(cfftw_data[i]), std::arg(cfftw_data[i])}; - } - for (size_t j = 1; j < navg; ++j) { - cfftw_data += cout_size; - for (size_t i = 0; i < cout_size; ++i) { - cout_data[i] += cplx_t(std::norm(cfftw_data[i]), std::arg(cfftw_data[i])); - } - } - const real_t avg_scalar = 1.0 / static_cast(navg); - real_t s = (RfftScale::Native == scale) ? 1.0 : k_sqrt2; - const real_t fft_scalar = s / static_cast(nfft); - for (size_t i = 0; i < cout_size; ++i) { - cplx_t& x = cout_data[i]; - x *= avg_scalar; - x = std::polar(std::sqrt(x.real()) * fft_scalar, x.imag()); - } - if (RfftScale::Native != scale) { - cout_data[0] /= k_sqrt2; - if (1 < nfft && is_even(nfft)) { - cout_data[cout_size - 1] /= k_sqrt2; - } - } - } - - void scale_fft(real_t* data, size_t nfft) - { - const size_t size = 2 * nfft; - const real_t scalar = 1.0 / static_cast(nfft); - for (size_t i = 0; i < size; ++i) { - data[i] *= scalar; - } - } - - void scale_rfft(real_t* data, size_t nfft, RfftScale scale) - { - const size_t size = (nfft / 2 + 1) * 2; - real_t s = (RfftScale::Native == scale) ? 1.0 : k_sqrt2; - const real_t scalar = s / static_cast(nfft); - for (size_t i = 0; i < size; ++i) { - data[i] *= scalar; - } - if (RfftScale::Native != scale) { - data[0] /= k_sqrt2; - data[1] /= k_sqrt2; - if (1 < nfft && is_even(nfft)) { - data[size - 1] /= k_sqrt2; - data[size - 2] /= k_sqrt2; - } - } - } - - } // namespace anonymous - - void fft( - const real_t* i_data, - size_t i_size, - const real_t* q_data, - size_t q_size, - real_t* out_data, - size_t out_size, - size_t navg, - size_t nfft, - Window window - ) - { - size_t in_stride = 1; - if (0 == q_size) { - // Interleaved I/Q - check_array("", "input array", i_data, i_size, true); - i_size /= 2; - q_size = i_size; - q_data = i_data + 1; - in_stride = 2; - } else { - // Split I/Q - check_array_pair("", "I array", i_data, i_size, "Q array", q_data, q_size); - } - check_array("", "output array", out_data, out_size); - size_t out_size_expected = fft_size(i_size, q_size, navg, nfft); // may modify navg and nfft - assert_eq("", "output array size", out_size, "expected", out_size_expected); - // If not averaging (1 == navg), use out_data directly. Otherwise, allocate temporary - // array to store result of normalization/windowing and FFT. For example, - // navg = 4, nfft = 16 - // => i_size = 64 - // q_size = 64 - // out_size = 16 * 2 = 32 - // tmp.size = navg * out_size = 128 - std::vector tmp ((1 == navg) ? 0 : 2 * i_size); - real_t* fftw_data = (1 == navg) ? out_data : tmp.data(); - switch (window) - { - case Window::BlackmanHarris: - blackman_harris(i_data, q_data, fftw_data, in_stride, navg, nfft); - break; - case Window::Hann: - hann(i_data, q_data, fftw_data, in_stride, navg, nfft); - break; - case Window::NoWindow: - no_window(i_data, q_data, fftw_data, in_stride, navg, nfft); - break; - default: - throw runtime_error("unsupported window"); - } - exec_fftw(fftw_data, navg, nfft); - if (1 == navg) { - scale_fft(out_data, nfft); - } else { - reduce_and_scale_fft(fftw_data, out_data, navg, nfft); - } - } - - template - void fft( - const T* i_data, - size_t i_size, - const T* q_data, - size_t q_size, - real_t* out_data, - size_t out_size, - int n, - size_t navg, - size_t nfft, - Window window, - CodeFormat format - ) - { - size_t in_stride = 1; - if (0 == q_size) { - // Interleaved I/Q - check_array("", "input array", i_data, i_size, true); - i_size /= 2; - q_size = i_size; - q_data = i_data + 1; - in_stride = 2; - } else { - // Split I/Q - check_array_pair("", "I array", i_data, i_size, "Q array", q_data, q_size); - } - check_array("", "output array", out_data, out_size); - size_t out_size_expected = fft_size(i_size, q_size, navg, nfft); // may modify navg and nfft - assert_eq("", "output array size", out_size, "expected", out_size_expected); - check_code_width("", n); - // If not averaging (1 == navg), use out_data directly. Otherwise, allocate temporary - // array to store result of normalization/windowing and FFT. For example, - // navg = 4, nfft = 16 - // => i_size = 64 - // q_size = 64 - // out_size = 16 * 2 = 32 - // tmp.size = navg * out_size = 128 - std::vector tmp ((1 == navg) ? 0 : 2 * i_size); - real_t* fftw_data = (1 == navg) ? out_data : tmp.data(); - switch (window) - { - case Window::BlackmanHarris: - norm_blackman_harris(i_data, q_data, fftw_data, in_stride, n, navg, nfft, format); - break; - case Window::Hann: - norm_hann(i_data, q_data, fftw_data, in_stride, n, navg, nfft, format); - break; - case Window::NoWindow: - norm_no_window(i_data, q_data, fftw_data, in_stride, n, navg, nfft, format); - break; - default: - throw runtime_error("unsupported window"); - } - exec_fftw(fftw_data, navg, nfft); - if (1 == navg) { - scale_fft(out_data, nfft); - } else { - reduce_and_scale_fft(fftw_data, out_data, navg, nfft); - } - } - - template void fft(const int16_t*, size_t, const int16_t*, size_t, real_t*, size_t, int, size_t, size_t, Window, CodeFormat); - template void fft(const int32_t*, size_t, const int32_t*, size_t, real_t*, size_t, int, size_t, size_t, Window, CodeFormat); - template void fft(const int64_t*, size_t, const int64_t*, size_t, real_t*, size_t, int, size_t, size_t, Window, CodeFormat); - - void rfft( - const real_t* in_data, - size_t in_size, - real_t* out_data, - size_t out_size, - size_t navg, - size_t nfft, - Window window, - RfftScale scale - ) - { - check_array("", "input array", in_data, in_size); - check_array("", "output array", out_data, out_size); - size_t out_size_expected = rfft_size(in_size, navg, nfft); - assert_eq("", "output array size", out_size, "expected", out_size_expected); - // If not averaging (1 == navg), use out_data directly. Otherwise, allocate temporary - // array to store result of windowing and FFT. For example, - // navg = 4, nfft = 16 - // => in_size = 64 - // out_size = (16/2 + 1) * 2 = 18 - // tmp.size = navg * out_size = 72 - std::vector tmp ((1 == navg) ? 0 : navg * out_size); - real_t* fftw_data = (1 == navg) ? out_data : tmp.data(); - switch (window) - { - case Window::BlackmanHarris: - blackman_harris(in_data, fftw_data, navg, nfft, scale); - break; - case Window::Hann: - hann(in_data, fftw_data, navg, nfft, scale); - break; - case Window::NoWindow: - no_window(in_data, fftw_data, navg, nfft, scale); - break; - default: - throw runtime_error("unsupported window"); - } - exec_rfftw(fftw_data, navg, nfft); - if (1 == navg) { - scale_rfft(out_data, nfft, scale); - } else { - reduce_and_scale_rfft(fftw_data, out_data, navg, nfft, scale); - } - } - - template - void rfft( - const T* in_data, - size_t in_size, - real_t* out_data, - size_t out_size, - int n, - size_t navg, - size_t nfft, - Window window, - CodeFormat format, - RfftScale scale - ) - { - check_array("", "input array", in_data, in_size); - check_array("", "output array", out_data, out_size); - size_t out_size_expected = rfft_size(in_size, navg, nfft); - assert_eq("", "output array size", out_size, "expected", out_size_expected); - check_code_width("", n); - // If not averaging (1 == navg), use out_data directly. Otherwise, allocate temporary - // array to store result of normalization/windowing and FFT. For example, - // navg = 4, nfft = 16 - // => in_size = 64 - // out_size = (16/2 + 1) * 2 = 18 - // tmp.size = navg * out_size = 72 - std::vector tmp ((1 == navg) ? 0 : navg * out_size); - real_t* fftw_data = (1 == navg) ? out_data : tmp.data(); - switch (window) - { - case Window::BlackmanHarris: - norm_blackman_harris(in_data, fftw_data, n, navg, nfft, format, scale); - break; - case Window::Hann: - norm_hann(in_data, fftw_data, n, navg, nfft, format, scale); - break; - case Window::NoWindow: - norm_no_window(in_data, fftw_data, n, navg, nfft, format, scale); - break; - default: - throw runtime_error("unsupported window"); - } - exec_rfftw(fftw_data, navg, nfft); - if (1 == navg) { - scale_rfft(out_data, nfft, scale); - } else { - reduce_and_scale_rfft(fftw_data, out_data, navg, nfft, scale); - } - } - - template void rfft(const int16_t*, size_t, real_t*, size_t, int, size_t, size_t, Window, CodeFormat, RfftScale); - template void rfft(const int32_t*, size_t, real_t*, size_t, int, size_t, size_t, Window, CodeFormat, RfftScale); - template void rfft(const int64_t*, size_t, real_t*, size_t, int, size_t, size_t, Window, CodeFormat, RfftScale); +namespace { // Window Function Constants + +const real_t blackman_harris_kx = 1.9688861870585801; +const real_t blackman_harris_k0 = 0.35875; +const real_t blackman_harris_k1 = -0.48829; +const real_t blackman_harris_k2 = 0.14128; +const real_t blackman_harris_k3 = -0.01168; +const real_t hann_kx = 1.6329922791756648; +const real_t hann_k0 = 0.5; +const real_t hann_k1 = -0.5; + +} // namespace + +namespace { // Window-Only Functions + +// For Complex FFT +void blackman_harris(const real_t *i_data, const real_t *q_data, + real_t *out_data, size_t in_stride, size_t navg, + size_t nfft) { + const real_t scalar = blackman_harris_kx; + const real_t k1 = k_2pi / static_cast(nfft); + const real_t k2 = k1 * 2; + const real_t k3 = k1 * 3; + const size_t in_row_stride = nfft * in_stride; + const size_t out_row_stride = nfft * 2; + size_t i = 0; + real_t x = 0.0; + if (1 == navg) { + for (size_t j = 0; j < out_row_stride; j += 2) { + const real_t w = blackman_harris_k0 + + blackman_harris_k1 * std::cos(k1 * x) + + blackman_harris_k2 * std::cos(k2 * x) + + blackman_harris_k3 * std::cos(k3 * x); + out_data[j] = w * scalar * i_data[i]; + out_data[j + 1] = w * scalar * q_data[i]; + i += in_stride; + x += 1.0; + } + } else if (2 == navg) { + const real_t *i2_data = i_data + in_row_stride; + const real_t *q2_data = q_data + in_row_stride; + real_t *out2_data = out_data + out_row_stride; + for (size_t j = 0; j < out_row_stride; j += 2) { + const real_t w = blackman_harris_k0 + + blackman_harris_k1 * std::cos(k1 * x) + + blackman_harris_k2 * std::cos(k2 * x) + + blackman_harris_k3 * std::cos(k3 * x); + out_data[j] = w * scalar * i_data[i]; + out_data[j + 1] = w * scalar * q_data[i]; + out2_data[j] = w * scalar * i2_data[i]; + out2_data[j + 1] = w * scalar * q2_data[i]; + i += in_stride; + x += 1.0; + } + } else { // 2 < navg + for (size_t j = 0; j < out_row_stride; j += 2) { + const real_t w = blackman_harris_k0 + + blackman_harris_k1 * std::cos(k1 * x) + + blackman_harris_k2 * std::cos(k2 * x) + + blackman_harris_k3 * std::cos(k3 * x); + const real_t *pi = i_data; + const real_t *pq = q_data; + real_t *po = out_data; + for (size_t k = 0; k < navg; ++k) { + po[j] = w * scalar * pi[i]; + po[j + 1] = w * scalar * pq[i]; + pi += in_row_stride; + pq += in_row_stride; + po += out_row_stride; + } + i += in_stride; + x += 1.0; + } + } +} + +// For Real FFT +void blackman_harris(const real_t *in_data, real_t *out_data, size_t navg, + size_t nfft, RfftScale scale) { + const real_t scalar = blackman_harris_kx * + ((RfftScale::DbfsSin == scale) ? k_sqrt2 : 1.0); + const real_t k1 = k_2pi / static_cast(nfft); + const real_t k2 = k1 * 2; + const real_t k3 = k1 * 3; + const size_t out_stride = (nfft / 2 + 1) * 2; + real_t x = 0.0; + if (1 == navg) { + for (size_t i = 0; i < nfft; ++i) { + const real_t w = blackman_harris_k0 + + blackman_harris_k1 * std::cos(k1 * x) + + blackman_harris_k2 * std::cos(k2 * x) + + blackman_harris_k3 * std::cos(k3 * x); + out_data[i] = w * scalar * in_data[i]; + x += 1.0; + } + } else if (2 == navg) { + const real_t *in2_data = in_data + nfft; + real_t *out2_data = out_data + out_stride; + for (size_t i = 0; i < nfft; ++i) { + const real_t w = blackman_harris_k0 + + blackman_harris_k1 * std::cos(k1 * x) + + blackman_harris_k2 * std::cos(k2 * x) + + blackman_harris_k3 * std::cos(k3 * x); + out_data[i] = w * scalar * in_data[i]; + out2_data[i] = w * scalar * in2_data[i]; + x += 1.0; + } + } else { // 2 < navg + for (size_t i = 0; i < nfft; ++i) { + const real_t w = blackman_harris_k0 + + blackman_harris_k1 * std::cos(k1 * x) + + blackman_harris_k2 * std::cos(k2 * x) + + blackman_harris_k3 * std::cos(k3 * x); + const real_t *pi = in_data; + real_t *po = out_data; + for (size_t j = 0; j < navg; ++j) { + po[i] = w * scalar * pi[i]; + pi += nfft; + po += out_stride; + } + x += 1.0; + } + } +} + +// For Complex FFT +void hann(const real_t *i_data, const real_t *q_data, real_t *out_data, + size_t in_stride, size_t navg, size_t nfft) { + const real_t scalar = hann_kx; + const real_t k1 = k_2pi / static_cast(nfft); + const size_t in_row_stride = nfft * in_stride; + const size_t out_row_stride = nfft * 2; + size_t i = 0; + real_t x = 0.0; + if (1 == navg) { + for (size_t j = 0; j < out_row_stride; j += 2) { + const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); + out_data[j] = w * scalar * i_data[i]; + out_data[j + 1] = w * scalar * q_data[i]; + i += in_stride; + x += 1.0; + } + } else if (2 == navg) { + const real_t *i2_data = i_data + nfft * in_stride; + const real_t *q2_data = q_data + nfft * in_stride; + real_t *out2_data = out_data + out_row_stride; + for (size_t j = 0; j < out_row_stride; j += 2) { + const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); + out_data[j] = w * scalar * i_data[i]; + out_data[j + 1] = w * scalar * q_data[i]; + out2_data[j] = w * scalar * i2_data[i]; + out2_data[j + 1] = w * scalar * q2_data[i]; + i += in_stride; + x += 1.0; + } + } else { // 2 < navg + for (size_t j = 0; j < out_row_stride; j += 2) { + const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); + const real_t *pi = i_data; + const real_t *pq = q_data; + real_t *po = out_data; + for (size_t k = 0; k < navg; ++k) { + po[j] = w * scalar * pi[i]; + po[j + 1] = w * scalar * pq[i]; + pi += in_row_stride; + pq += in_row_stride; + po += out_row_stride; + } + i += in_stride; + x += 1.0; + } + } +} + +// For Real FFT +void hann(const real_t *in_data, real_t *out_data, size_t navg, size_t nfft, + RfftScale scale) { + const real_t scalar = + hann_kx * ((RfftScale::DbfsSin == scale) ? k_sqrt2 : 1.0); + const real_t k1 = k_2pi / static_cast(nfft); + const size_t out_stride = (nfft / 2 + 1) * 2; + real_t x = 0.0; + if (1 == navg) { + for (size_t i = 0; i < nfft; ++i) { + const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); + out_data[i] = w * scalar * in_data[i]; + x += 1.0; + } + } else if (2 == navg) { + const real_t *in2_data = in_data + nfft; + real_t *out2_data = out_data + out_stride; + for (size_t i = 0; i < nfft; ++i) { + const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); + out_data[i] = w * scalar * in_data[i]; + out2_data[i] = w * scalar * in2_data[i]; + x += 1.0; + } + } else { // 2 < navg + for (size_t i = 0; i < nfft; ++i) { + const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); + const real_t *pi = in_data; + real_t *po = out_data; + for (size_t j = 0; j < navg; ++j) { + po[i] = w * scalar * pi[i]; + pi += nfft; + po += out_stride; + } + x += 1.0; + } + } +} + +// For Complex FFT +void no_window(const real_t *i_data, const real_t *q_data, real_t *out_data, + size_t in_stride, size_t navg, size_t nfft) { + const size_t out_size = navg * nfft * 2; + size_t i = 0; + for (size_t j = 0; j < out_size; j += 2) { + out_data[j] = i_data[i]; + out_data[j + 1] = q_data[i]; + i += in_stride; + } +} + +// For Real FFT +void no_window(const real_t *in_data, real_t *out_data, size_t navg, + size_t nfft, RfftScale scale) { + const real_t scalar = (RfftScale::DbfsSin == scale) ? k_sqrt2 : 1.0; + const size_t out_stride = (nfft / 2 + 1) * 2; + for (size_t j = 0; j < navg; ++j) { + for (size_t i = 0; i < nfft; ++i) { + out_data[i] = scalar * in_data[i]; + } + in_data += nfft; + out_data += out_stride; + } +} + +} // namespace + +namespace { // Normalize-Window Functions + +// For Complex FFT +template +void norm_blackman_harris(const T *i_data, const T *q_data, real_t *out_data, + size_t in_stride, int n, size_t navg, size_t nfft, + CodeFormat format) { + const real_t scalar = blackman_harris_kx * 2.0 / (1 << n); + const real_t offset = (CodeFormat::OffsetBinary == format) ? -blackman_harris_kx : 0.0; + const real_t k1 = k_2pi / static_cast(nfft); + const real_t k2 = k1 * 2; + const real_t k3 = k1 * 3; + const size_t in_row_stride = nfft * in_stride; + const size_t out_row_stride = nfft * 2; + size_t i = 0; + real_t x = 0.0; + if (1 == navg) { + for (size_t j = 0; j < out_row_stride; j += 2) { + const real_t w = blackman_harris_k0 + + blackman_harris_k1 * std::cos(k1 * x) + + blackman_harris_k2 * std::cos(k2 * x) + + blackman_harris_k3 * std::cos(k3 * x); + out_data[j] = + w * std::fma(scalar, static_cast(i_data[i]), offset); + out_data[j + 1] = + w * std::fma(scalar, static_cast(q_data[i]), offset); + i += in_stride; + x += 1.0; + } + } else if (2 == navg) { + const T *i2_data = i_data + in_row_stride; + const T *q2_data = q_data + in_row_stride; + real_t *out2_data = out_data + out_row_stride; + for (size_t j = 0; j < out_row_stride; j += 2) { + const real_t w = blackman_harris_k0 + + blackman_harris_k1 * std::cos(k1 * x) + + blackman_harris_k2 * std::cos(k2 * x) + + blackman_harris_k3 * std::cos(k3 * x); + out_data[j] = + w * std::fma(scalar, static_cast(i_data[i]), offset); + out_data[j + 1] = + w * std::fma(scalar, static_cast(q_data[i]), offset); + out2_data[j] = + w * std::fma(scalar, static_cast(i2_data[i]), offset); + out2_data[j + 1] = + w * std::fma(scalar, static_cast(q2_data[i]), offset); + i += in_stride; + x += 1.0; + } + } else { // 2 < navg + for (size_t j = 0; j < out_row_stride; j += 2) { + const real_t w = blackman_harris_k0 + + blackman_harris_k1 * std::cos(k1 * x) + + blackman_harris_k2 * std::cos(k2 * x) + + blackman_harris_k3 * std::cos(k3 * x); + const T *pi = i_data; + const T *pq = q_data; + real_t *po = out_data; + for (size_t k = 0; k < navg; ++k) { + po[j] = w * std::fma(scalar, static_cast(pi[i]), offset); + po[j + 1] = + w * std::fma(scalar, static_cast(pq[i]), offset); + pi += in_row_stride; + pq += in_row_stride; + po += out_row_stride; + } + i += in_stride; + x += 1.0; + } + } +} + +// For Real FFT +template +void norm_blackman_harris(const T *in_data, real_t *out_data, int n, + size_t navg, size_t nfft, CodeFormat format, + RfftScale scale) { + real_t s = blackman_harris_kx * + ((RfftScale::DbfsSin == scale) ? k_sqrt2 : 1.0); + const real_t scalar = s * 2.0 / (1 << n); + const real_t offset = (CodeFormat::OffsetBinary == format) ? -s : 0.0; + const real_t k1 = k_2pi / static_cast(nfft); + const real_t k2 = k1 * 2; + const real_t k3 = k1 * 3; + const size_t out_stride = (nfft / 2 + 1) * 2; + real_t x = 0.0; + if (1 == navg) { + for (size_t i = 0; i < nfft; ++i) { + const real_t w = blackman_harris_k0 + + blackman_harris_k1 * std::cos(k1 * x) + + blackman_harris_k2 * std::cos(k2 * x) + + blackman_harris_k3 * std::cos(k3 * x); + out_data[i] = + w * std::fma(scalar, static_cast(in_data[i]), offset); + x += 1.0; + } + } else if (2 == navg) { + const T *in2_data = in_data + nfft; + real_t *out2_data = out_data + out_stride; + for (size_t i = 0; i < nfft; ++i) { + const real_t w = blackman_harris_k0 + + blackman_harris_k1 * std::cos(k1 * x) + + blackman_harris_k2 * std::cos(k2 * x) + + blackman_harris_k3 * std::cos(k3 * x); + out_data[i] = + w * std::fma(scalar, static_cast(in_data[i]), offset); + out2_data[i] = + w * std::fma(scalar, static_cast(in2_data[i]), offset); + x += 1.0; + } + } else { // 2 < navg + for (size_t i = 0; i < nfft; ++i) { + const real_t w = blackman_harris_k0 + + blackman_harris_k1 * std::cos(k1 * x) + + blackman_harris_k2 * std::cos(k2 * x) + + blackman_harris_k3 * std::cos(k3 * x); + const T *pi = in_data; + real_t *po = out_data; + for (size_t j = 0; j < navg; ++j) { + po[i] = w * std::fma(scalar, static_cast(pi[i]), offset); + pi += nfft; + po += out_stride; + } + x += 1.0; + } + } +} + +// For Complex FFT +template +void norm_hann(const T *i_data, const T *q_data, real_t *out_data, + size_t in_stride, int n, size_t navg, size_t nfft, + CodeFormat format) { + const real_t scalar = hann_kx * 2.0 / (1 << n); + const real_t offset = (CodeFormat::OffsetBinary == format) ? -hann_kx : 0.0; + const real_t k1 = k_2pi / static_cast(nfft); + const size_t in_row_stride = nfft * in_stride; + const size_t out_row_stride = nfft * 2; + size_t i = 0; + real_t x = 0.0; + if (1 == navg) { + for (size_t j = 0; j < out_row_stride; j += 2) { + const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); + out_data[j] = + w * std::fma(scalar, static_cast(i_data[i]), offset); + out_data[j + 1] = + w * std::fma(scalar, static_cast(q_data[i]), offset); + i += in_stride; + x += 1.0; + } + } else if (2 == navg) { + const T *i2_data = i_data + nfft * in_stride; + const T *q2_data = q_data + nfft * in_stride; + real_t *out2_data = out_data + out_row_stride; + for (size_t j = 0; j < out_row_stride; j += 2) { + const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); + out_data[j] = + w * std::fma(scalar, static_cast(i_data[i]), offset); + out_data[j + 1] = + w * std::fma(scalar, static_cast(q_data[i]), offset); + out2_data[j] = + w * std::fma(scalar, static_cast(i2_data[i]), offset); + out2_data[j + 1] = + w * std::fma(scalar, static_cast(q2_data[i]), offset); + i += in_stride; + x += 1.0; + } + } else { // 2 < navg + for (size_t j = 0; j < out_row_stride; j += 2) { + const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); + const T *pi = i_data; + const T *pq = q_data; + real_t *po = out_data; + for (size_t k = 0; k < navg; ++k) { + po[j] = w * std::fma(scalar, static_cast(pi[i]), offset); + po[j + 1] = + w * std::fma(scalar, static_cast(pq[i]), offset); + pi += in_row_stride; + pq += in_row_stride; + po += out_row_stride; + } + i += in_stride; + x += 1.0; + } + } +} + +// For Real FFT +template +void norm_hann(const T *in_data, real_t *out_data, int n, size_t navg, + size_t nfft, CodeFormat format, RfftScale scale) { + real_t s = hann_kx * ((RfftScale::DbfsSin == scale) ? k_sqrt2 : 1.0); + const real_t scalar = s * 2.0 / (1 << n); + const real_t offset = (CodeFormat::OffsetBinary == format) ? -s : 0.0; + const real_t k1 = k_2pi / static_cast(nfft); + const size_t out_stride = (nfft / 2 + 1) * 2; + real_t x = 0.0; + if (1 == navg) { + for (size_t i = 0; i < nfft; ++i) { + const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); + out_data[i] = + w * std::fma(scalar, static_cast(in_data[i]), offset); + x += 1.0; + } + } else if (2 == navg) { + const T *in2_data = in_data + nfft; + real_t *out2_data = out_data + out_stride; + for (size_t i = 0; i < nfft; ++i) { + const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); + out_data[i] = + w * std::fma(scalar, static_cast(in_data[i]), offset); + out2_data[i] = + w * std::fma(scalar, static_cast(in2_data[i]), offset); + x += 1.0; + } + } else { // 2 < navg + for (size_t i = 0; i < nfft; ++i) { + const real_t w = hann_k0 + hann_k1 * std::cos(k1 * x); + const T *pi = in_data; + real_t *po = out_data; + for (size_t j = 0; j < navg; ++j) { + po[i] = w * std::fma(scalar, static_cast(pi[i]), offset); + pi += nfft; + po += out_stride; + } + x += 1.0; + } + } +} + +// For Complex FFT +template +void norm_no_window(const T *i_data, const T *q_data, real_t *out_data, + size_t in_stride, int n, size_t navg, size_t nfft, + CodeFormat format) { + const real_t scalar = 2.0 / (1 << n); + const real_t offset = (CodeFormat::OffsetBinary == format) ? -1.0 : 0.0; + const size_t out_size = navg * nfft * 2; + size_t i = 0; + for (size_t j = 0; j < out_size; j += 2) { + out_data[j] = std::fma(scalar, static_cast(i_data[i]), + offset); + out_data[j + 1] = std::fma( + scalar, static_cast(q_data[i]), offset); + i += in_stride; + } +} + +// For Real FFT +template +void norm_no_window(const T *in_data, real_t *out_data, int n, size_t navg, + size_t nfft, CodeFormat format, RfftScale scale) { + real_t s = (RfftScale::DbfsSin == scale) ? k_sqrt2 : 1.0; + const real_t scalar = s * 2.0 / (1 << n); + const real_t offset = (CodeFormat::OffsetBinary == format) ? -s : 0.0; + const size_t out_stride = (nfft / 2 + 1) * 2; + for (size_t j = 0; j < navg; ++j) { + for (size_t i = 0; i < nfft; ++i) { + out_data[i] = std::fma(scalar, + static_cast(in_data[i]), + offset); + } + in_data += nfft; + out_data += out_stride; + } +} + +} // namespace + +namespace { // FFTW Functions + +void exec_fftw(real_t *data, size_t navg, size_t nfft) { + diff_t navg_ = static_cast(navg); + diff_t nfft_ = static_cast(nfft); + // FFT size: FFTW "rank" and "dims" + int rank = 1; + fftw_iodim64 dims{ nfft_, 2, 2 }; + // FFT averaging: FFTW "howmany_rank" and "howmany_dims" + int howmany_rank = 1; + fftw_iodim64 howmany_dims = { navg_, nfft_ * 2, nfft_ * 2 }; + // FFTW plan setup and execution + fftw_plan plan = fftw_plan_guru64_split_dft(rank, &dims, howmany_rank, + &howmany_dims, + data, // I input + data + 1, // Q input + data, // Re output + data + 1, // Im output + FFTW_ESTIMATE); + if (nullptr == plan) { + throw runtime_error("FFTW Plan is NULL"); + } + fftw_execute(plan); + fftw_destroy_plan(plan); +} + +void exec_rfftw(real_t *data, size_t navg, size_t nfft) { + diff_t navg_ = static_cast(navg); + diff_t nfft_ = static_cast(nfft); + diff_t out_stride = nfft_ / 2 + 1; + // FFT size: FFTW "rank" and "dims" + int rank = 1; + fftw_iodim64 dims{ nfft_, 1, 1 }; + // FFT averaging: FFTW "howmany_rank" and "howmany_dims" + int howmany_rank = 1; + fftw_iodim64 howmany_dims{ navg_, out_stride * 2, out_stride }; + // Plan setup and execution + fftw_complex *out_data = reinterpret_cast(data); + fftw_plan plan = fftw_plan_guru64_dft_r2c(rank, &dims, howmany_rank, + &howmany_dims, data, out_data, + FFTW_ESTIMATE); + if (nullptr == plan) { + throw runtime_error("FFTW Plan is NULL"); + } + fftw_execute(plan); + fftw_destroy_plan(plan); +} + +} // namespace + +namespace { // Scaling and Averaging Functions + +void reduce_and_scale_fft(real_t *fftw_data, real_t *out_data, size_t navg, + size_t nfft) { + cplx_t *cfftw_data = reinterpret_cast(fftw_data); + cplx_t *cout_data = reinterpret_cast(out_data); + for (size_t i = 0; i < nfft; ++i) { + cout_data[i] = { std::norm(cfftw_data[i]), + std::arg(cfftw_data[i]) }; + } + for (size_t j = 1; j < navg; ++j) { + cfftw_data += nfft; + for (size_t i = 0; i < nfft; ++i) { + cout_data[i] += cplx_t(std::norm(cfftw_data[i]), + std::arg(cfftw_data[i])); + } + } + const real_t avg_scalar = 1.0 / static_cast(navg); + const real_t fft_scalar = 1.0 / static_cast(nfft); + for (size_t i = 0; i < nfft; ++i) { + cplx_t &x = cout_data[i]; + x *= avg_scalar; + x = std::polar(std::sqrt(x.real()) * fft_scalar, x.imag()); + } +} + +void reduce_and_scale_rfft(real_t *fftw_data, real_t *out_data, size_t navg, + size_t nfft, RfftScale scale) { + cplx_t *cfftw_data = reinterpret_cast(fftw_data); + cplx_t *cout_data = reinterpret_cast(out_data); + const size_t cout_size = nfft / 2 + 1; + for (size_t i = 0; i < cout_size; ++i) { + cout_data[i] = { std::norm(cfftw_data[i]), + std::arg(cfftw_data[i]) }; + } + for (size_t j = 1; j < navg; ++j) { + cfftw_data += cout_size; + for (size_t i = 0; i < cout_size; ++i) { + cout_data[i] += cplx_t(std::norm(cfftw_data[i]), + std::arg(cfftw_data[i])); + } + } + const real_t avg_scalar = 1.0 / static_cast(navg); + real_t s = (RfftScale::Native == scale) ? 1.0 : k_sqrt2; + const real_t fft_scalar = s / static_cast(nfft); + for (size_t i = 0; i < cout_size; ++i) { + cplx_t &x = cout_data[i]; + x *= avg_scalar; + x = std::polar(std::sqrt(x.real()) * fft_scalar, x.imag()); + } + if (RfftScale::Native != scale) { + cout_data[0] /= k_sqrt2; + if (1 < nfft && is_even(nfft)) { + cout_data[cout_size - 1] /= k_sqrt2; + } + } +} + +void scale_fft(real_t *data, size_t nfft) { + const size_t size = 2 * nfft; + const real_t scalar = 1.0 / static_cast(nfft); + for (size_t i = 0; i < size; ++i) { + data[i] *= scalar; + } +} + +void scale_rfft(real_t *data, size_t nfft, RfftScale scale) { + const size_t size = (nfft / 2 + 1) * 2; + real_t s = (RfftScale::Native == scale) ? 1.0 : k_sqrt2; + const real_t scalar = s / static_cast(nfft); + for (size_t i = 0; i < size; ++i) { + data[i] *= scalar; + } + if (RfftScale::Native != scale) { + data[0] /= k_sqrt2; + data[1] /= k_sqrt2; + if (1 < nfft && is_even(nfft)) { + data[size - 1] /= k_sqrt2; + data[size - 2] /= k_sqrt2; + } + } +} + +} // namespace + +void fft(const real_t *i_data, size_t i_size, const real_t *q_data, + size_t q_size, real_t *out_data, size_t out_size, size_t navg, + size_t nfft, Window window) { + size_t in_stride = 1; + if (0 == q_size) { + // Interleaved I/Q + check_array("", "input array", i_data, i_size, true); + i_size /= 2; + q_size = i_size; + q_data = i_data + 1; + in_stride = 2; + } else { + // Split I/Q + check_array_pair("", "I array", i_data, i_size, "Q array", + q_data, q_size); + } + check_array("", "output array", out_data, out_size); + size_t out_size_expected = fft_size(i_size, q_size, navg, + nfft); // may modify navg and nfft + assert_eq("", "output array size", out_size, "expected", + out_size_expected); + // If not averaging (1 == navg), use out_data directly. Otherwise, allocate + // temporary array to store result of normalization/windowing and FFT. For + // example, + // navg = 4, nfft = 16 + // => i_size = 64 + // q_size = 64 + // out_size = 16 * 2 = 32 + // tmp.size = navg * out_size = 128 + std::vector tmp((1 == navg) ? 0 : 2 * i_size); + real_t *fftw_data = (1 == navg) ? out_data : tmp.data(); + switch (window) { + case Window::BlackmanHarris: + blackman_harris(i_data, q_data, fftw_data, in_stride, navg, + nfft); + break; + case Window::Hann: + hann(i_data, q_data, fftw_data, in_stride, navg, nfft); + break; + case Window::NoWindow: + no_window(i_data, q_data, fftw_data, in_stride, navg, nfft); + break; + default: + throw runtime_error("unsupported window"); + } + exec_fftw(fftw_data, navg, nfft); + if (1 == navg) { + scale_fft(out_data, nfft); + } else { + reduce_and_scale_fft(fftw_data, out_data, navg, nfft); + } +} + +template +void fft(const T *i_data, size_t i_size, const T *q_data, size_t q_size, + real_t *out_data, size_t out_size, int n, size_t navg, size_t nfft, + Window window, CodeFormat format) { + size_t in_stride = 1; + if (0 == q_size) { + // Interleaved I/Q + check_array("", "input array", i_data, i_size, true); + i_size /= 2; + q_size = i_size; + q_data = i_data + 1; + in_stride = 2; + } else { + // Split I/Q + check_array_pair("", "I array", i_data, i_size, "Q array", + q_data, q_size); + } + check_array("", "output array", out_data, out_size); + size_t out_size_expected = fft_size(i_size, q_size, navg, + nfft); // may modify navg and nfft + assert_eq("", "output array size", out_size, "expected", + out_size_expected); + check_code_width("", n); + // If not averaging (1 == navg), use out_data directly. Otherwise, allocate + // temporary array to store result of normalization/windowing and FFT. For + // example, + // navg = 4, nfft = 16 + // => i_size = 64 + // q_size = 64 + // out_size = 16 * 2 = 32 + // tmp.size = navg * out_size = 128 + std::vector tmp((1 == navg) ? 0 : 2 * i_size); + real_t *fftw_data = (1 == navg) ? out_data : tmp.data(); + switch (window) { + case Window::BlackmanHarris: + norm_blackman_harris(i_data, q_data, fftw_data, in_stride, n, + navg, nfft, format); + break; + case Window::Hann: + norm_hann(i_data, q_data, fftw_data, in_stride, n, navg, nfft, + format); + break; + case Window::NoWindow: + norm_no_window(i_data, q_data, fftw_data, in_stride, n, navg, + nfft, format); + break; + default: + throw runtime_error("unsupported window"); + } + exec_fftw(fftw_data, navg, nfft); + if (1 == navg) { + scale_fft(out_data, nfft); + } else { + reduce_and_scale_fft(fftw_data, out_data, navg, nfft); + } +} + +template void fft(const int16_t *, size_t, const int16_t *, size_t, real_t *, + size_t, int, size_t, size_t, Window, CodeFormat); +template void fft(const int32_t *, size_t, const int32_t *, size_t, real_t *, + size_t, int, size_t, size_t, Window, CodeFormat); +template void fft(const int64_t *, size_t, const int64_t *, size_t, real_t *, + size_t, int, size_t, size_t, Window, CodeFormat); + +void rfft(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size, size_t navg, size_t nfft, Window window, + RfftScale scale) { + check_array("", "input array", in_data, in_size); + check_array("", "output array", out_data, out_size); + size_t out_size_expected = rfft_size(in_size, navg, nfft); + assert_eq("", "output array size", out_size, "expected", + out_size_expected); + // If not averaging (1 == navg), use out_data directly. Otherwise, allocate + // temporary array to store result of windowing and FFT. For example, + // navg = 4, nfft = 16 + // => in_size = 64 + // out_size = (16/2 + 1) * 2 = 18 + // tmp.size = navg * out_size = 72 + std::vector tmp((1 == navg) ? 0 : navg * out_size); + real_t *fftw_data = (1 == navg) ? out_data : tmp.data(); + switch (window) { + case Window::BlackmanHarris: + blackman_harris(in_data, fftw_data, navg, nfft, scale); + break; + case Window::Hann: + hann(in_data, fftw_data, navg, nfft, scale); + break; + case Window::NoWindow: + no_window(in_data, fftw_data, navg, nfft, scale); + break; + default: + throw runtime_error("unsupported window"); + } + exec_rfftw(fftw_data, navg, nfft); + if (1 == navg) { + scale_rfft(out_data, nfft, scale); + } else { + reduce_and_scale_rfft(fftw_data, out_data, navg, nfft, scale); + } +} + +template +void rfft(const T *in_data, size_t in_size, real_t *out_data, size_t out_size, + int n, size_t navg, size_t nfft, Window window, CodeFormat format, + RfftScale scale) { + check_array("", "input array", in_data, in_size); + check_array("", "output array", out_data, out_size); + size_t out_size_expected = rfft_size(in_size, navg, nfft); + assert_eq("", "output array size", out_size, "expected", + out_size_expected); + check_code_width("", n); + // If not averaging (1 == navg), use out_data directly. Otherwise, allocate + // temporary array to store result of normalization/windowing and FFT. For + // example, + // navg = 4, nfft = 16 + // => in_size = 64 + // out_size = (16/2 + 1) * 2 = 18 + // tmp.size = navg * out_size = 72 + std::vector tmp((1 == navg) ? 0 : navg * out_size); + real_t *fftw_data = (1 == navg) ? out_data : tmp.data(); + switch (window) { + case Window::BlackmanHarris: + norm_blackman_harris(in_data, fftw_data, n, navg, nfft, format, + scale); + break; + case Window::Hann: + norm_hann(in_data, fftw_data, n, navg, nfft, format, scale); + break; + case Window::NoWindow: + norm_no_window(in_data, fftw_data, n, navg, nfft, format, + scale); + break; + default: + throw runtime_error("unsupported window"); + } + exec_rfftw(fftw_data, navg, nfft); + if (1 == navg) { + scale_rfft(out_data, nfft, scale); + } else { + reduce_and_scale_rfft(fftw_data, out_data, navg, nfft, scale); + } +} + +template void rfft(const int16_t *, size_t, real_t *, size_t, int, size_t, + size_t, Window, CodeFormat, RfftScale); +template void rfft(const int32_t *, size_t, real_t *, size_t, int, size_t, + size_t, Window, CodeFormat, RfftScale); +template void rfft(const int64_t *, size_t, real_t *, size_t, int, size_t, + size_t, Window, CodeFormat, RfftScale); } // namespace genalyzer_impl namespace genalyzer_impl { - namespace { - - // fft: in_size is the size of either the I or Q waveform (not the sum) - // rfft: in_size is the size of the waveform - void resolve_navg_and_nfft(const size_t in_size, size_t& navg, size_t& nfft) - { - assert_gt0("", "input size", in_size); - if (k_abs_max_fft_navg < navg) { - throw runtime_error("navg (" + std::to_string(navg) - + ") exceeds limit (" + std::to_string(k_abs_max_fft_navg) + ")"); - } - if (0 == navg && 0 == nfft) { - navg = 1; - nfft = in_size; - } else if (0 == navg) { - navg = in_size / nfft; - if (0 == navg) { - throw runtime_error("derived navg == 0"); - } - if (k_abs_max_fft_navg < navg) { - throw runtime_error("derived navg (" + std::to_string(navg) - + ") exceeds limit (" + std::to_string(k_abs_max_fft_navg) + ")"); - } - } else if (0 == nfft) { - nfft = in_size / navg; - } - size_t in_size_expected = navg * nfft; - try { - assert_eq("", "input size", in_size, "expected", in_size_expected); - } catch (const std::exception& e) { - throw runtime_error(str_t(e.what()) + "\nExpected input size = navg * nfft = " - + std::to_string(navg) + " * " + std::to_string(nfft) + " = " - + std::to_string(in_size_expected) + "\nGot input size = " - + std::to_string(in_size)); - } - } - - } // namespace anonymous - - size_t fft_size(size_t i_size, size_t q_size, size_t& navg, size_t& nfft) - { - if (0 == q_size) { - if (is_odd(i_size)) { - throw runtime_error("size of interleaved array must be even"); - } - i_size /= 2; - } else { - assert_eq("", "I size", i_size, "Q size", q_size); - } - resolve_navg_and_nfft(i_size, navg, nfft); - size_t size = nfft * 2; - return size; - } - - size_t rfft_size(size_t in_size, size_t& navg, size_t& nfft) - { - resolve_navg_and_nfft(in_size, navg, nfft); - size_t size = (nfft / 2 + 1) * 2; // integer division intentional - return size; - } +namespace { + +// fft: in_size is the size of either the I or Q waveform (not the sum) +// rfft: in_size is the size of the waveform +void resolve_navg_and_nfft(const size_t in_size, size_t &navg, size_t &nfft) { + assert_gt0("", "input size", in_size); + if (k_abs_max_fft_navg < navg) { + throw runtime_error("navg (" + std::to_string(navg) + + ") exceeds limit (" + + std::to_string(k_abs_max_fft_navg) + ")"); + } + if (0 == navg && 0 == nfft) { + navg = 1; + nfft = in_size; + } else if (0 == navg) { + navg = in_size / nfft; + if (0 == navg) { + throw runtime_error("derived navg == 0"); + } + if (k_abs_max_fft_navg < navg) { + throw runtime_error( + "derived navg (" + std::to_string(navg) + + ") exceeds limit (" + + std::to_string(k_abs_max_fft_navg) + ")"); + } + } else if (0 == nfft) { + nfft = in_size / navg; + } + size_t in_size_expected = navg * nfft; + try { + assert_eq("", "input size", in_size, "expected", + in_size_expected); + } catch (const std::exception &e) { + throw runtime_error( + str_t(e.what()) + + "\nExpected input size = navg * nfft = " + + std::to_string(navg) + " * " + std::to_string(nfft) + + " = " + std::to_string(in_size_expected) + + "\nGot input size = " + std::to_string(in_size)); + } +} + +} // namespace + +size_t fft_size(size_t i_size, size_t q_size, size_t &navg, size_t &nfft) { + if (0 == q_size) { + if (is_odd(i_size)) { + throw runtime_error( + "size of interleaved array must be even"); + } + i_size /= 2; + } else { + assert_eq("", "I size", i_size, "Q size", q_size); + } + resolve_navg_and_nfft(i_size, navg, nfft); + size_t size = nfft * 2; + return size; +} + +size_t rfft_size(size_t in_size, size_t &navg, size_t &nfft) { + resolve_navg_and_nfft(in_size, navg, nfft); + size_t size = (nfft / 2 + 1) * 2; // integer division intentional + return size; +} } // namespace genalyzer_impl \ No newline at end of file diff --git a/src/fourier_utilities.cpp b/src/fourier_utilities.cpp index a41b97c..b62ea41 100644 --- a/src/fourier_utilities.cpp +++ b/src/fourier_utilities.cpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #include "fourier_utilities.hpp" #include "constants.hpp" @@ -11,100 +14,95 @@ namespace genalyzer_impl { - real_t alias(real_t fs, real_t freq, FreqAxisType axis_type) - { - assert_gt0("", "fs", fs); - freq -= std::floor(freq / fs) * fs; // freq in [0, fs) - if (FreqAxisType::DcCenter == axis_type) { - return (fs <= 2 * freq) ? (freq - fs) : freq; - } else if (FreqAxisType::Real == axis_type) { - return (fs < 2 * freq) ? (fs - freq) : freq; - } else { - return freq; - } - } +real_t alias(real_t fs, real_t freq, FreqAxisType axis_type) { + assert_gt0("", "fs", fs); + freq -= std::floor(freq / fs) * fs; // freq in [0, fs) + if (FreqAxisType::DcCenter == axis_type) { + return (fs <= 2 * freq) ? (freq - fs) : freq; + } else if (FreqAxisType::Real == axis_type) { + return (fs < 2 * freq) ? (fs - freq) : freq; + } else { + return freq; + } +} - real_t coherent(size_t nfft, real_t fs, real_t freq) - { - assert_gt0("", "nfft", nfft); - assert_gt0("", "fs", fs); - if (1 == nfft) { - return freq; - } - real_t fbin = fs / static_cast(nfft); - assert_gt0("", "fbin", fbin); - real_t cycles = std::fabs(freq) / fbin; - if (is_pow2(nfft)) { - cycles = std::floor(cycles); - if (0.0 == std::fmod(cycles, 2.0)) { - cycles += 1.0; - } - cycles = std::copysign(cycles, freq); - } else { - cycles = std::copysign(std::round(cycles), freq); - } - return cycles * fbin; - } +real_t coherent(size_t nfft, real_t fs, real_t freq) { + assert_gt0("", "nfft", nfft); + assert_gt0("", "fs", fs); + if (1 == nfft) { + return freq; + } + real_t fbin = fs / static_cast(nfft); + assert_gt0("", "fbin", fbin); + real_t cycles = std::fabs(freq) / fbin; + if (is_pow2(nfft)) { + cycles = std::floor(cycles); + if (0.0 == std::fmod(cycles, 2.0)) { + cycles += 1.0; + } + cycles = std::copysign(cycles, freq); + } else { + cycles = std::copysign(std::round(cycles), freq); + } + return cycles * fbin; +} - void fftshift(const real_t* in_data, size_t in_size, real_t* out_data, size_t out_size) - { - check_array_pair("", "input array", in_data, in_size, "output_array", out_data, out_size); - size_t offset = in_size / 2; - if (is_odd(in_size)) { - offset += 1; - } - if (in_data == out_data) { - std::rotate(out_data, out_data + offset, out_data + out_size); - } else { - std::rotate_copy(in_data, in_data + offset, in_data + in_size, out_data); - } - } +void fftshift(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size) { + check_array_pair("", "input array", in_data, in_size, "output_array", + out_data, out_size); + size_t offset = in_size / 2; + if (is_odd(in_size)) { + offset += 1; + } + if (in_data == out_data) { + std::rotate(out_data, out_data + offset, out_data + out_size); + } else { + std::rotate_copy(in_data, in_data + offset, in_data + in_size, + out_data); + } +} - void freq_axis( - real_t* data, - size_t size, - size_t nfft, - FreqAxisType axis_type, - real_t fs, - FreqAxisFormat axis_format - ) - { - check_array("", "output array", data, size); - assert_eq("", "array size", size, "expected", freq_axis_size(nfft, axis_type)); - real_t start = 0.0; - if (FreqAxisType::DcCenter == axis_type) { - start = -static_cast(nfft / 2); - } - std::iota(data, data + size, start); - real_t unit = 1.0; - if (FreqAxisFormat::Freq == axis_format) { - unit = fs / static_cast(nfft); - } else if (FreqAxisFormat::Norm == axis_format) { - unit /= static_cast(nfft); - } - if (1.0 != unit) { - for (size_t i = 0; i < size; ++i) { - data[i] *= unit; - } - } - } +void freq_axis(real_t *data, size_t size, size_t nfft, FreqAxisType axis_type, + real_t fs, FreqAxisFormat axis_format) { + check_array("", "output array", data, size); + assert_eq("", "array size", size, "expected", + freq_axis_size(nfft, axis_type)); + real_t start = 0.0; + if (FreqAxisType::DcCenter == axis_type) { + start = -static_cast(nfft / 2); + } + std::iota(data, data + size, start); + real_t unit = 1.0; + if (FreqAxisFormat::Freq == axis_format) { + unit = fs / static_cast(nfft); + } else if (FreqAxisFormat::Norm == axis_format) { + unit /= static_cast(nfft); + } + if (1.0 != unit) { + for (size_t i = 0; i < size; ++i) { + data[i] *= unit; + } + } +} - void ifftshift(const real_t* in_data, size_t in_size, real_t* out_data, size_t out_size) - { - check_array_pair("", "input array", in_data, in_size, "output_array", out_data, out_size); - size_t offset = in_size / 2; - if (in_data == out_data) { - std::rotate(out_data, out_data + offset, out_data + out_size); - } else { - std::rotate_copy(in_data, in_data + offset, in_data + in_size, out_data); - } - } +void ifftshift(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size) { + check_array_pair("", "input array", in_data, in_size, "output_array", + out_data, out_size); + size_t offset = in_size / 2; + if (in_data == out_data) { + std::rotate(out_data, out_data + offset, out_data + out_size); + } else { + std::rotate_copy(in_data, in_data + offset, in_data + in_size, + out_data); + } +} - size_t freq_axis_size(size_t nfft, FreqAxisType axis_type) - { - assert_gt0("", "nfft", nfft); - size_t size = (FreqAxisType::Real == axis_type) ? nfft / 2 + 1 : nfft; - return size; - } +size_t freq_axis_size(size_t nfft, FreqAxisType axis_type) { + assert_gt0("", "nfft", nfft); + size_t size = (FreqAxisType::Real == axis_type) ? nfft / 2 + 1 : nfft; + return size; +} } // namespace genalyzer_impl \ No newline at end of file diff --git a/src/json.cpp b/src/json.cpp index f9ed285..1eb4ae4 100644 --- a/src/json.cpp +++ b/src/json.cpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #include "fourier_analysis.hpp" #include @@ -13,130 +16,135 @@ using json = nlohmann::json; namespace genalyzer_impl { - std::shared_ptr fourier_analysis::load(const str_t& filename) - { - std::ifstream ifs (filename); - if (!ifs.is_open()) { - throw runtime_error("unable to open file '" + filename + "'"); - } - try { - json j; - ifs >> j; // error handling? - std::shared_ptr p = std::make_shared(); - j["en_conv_offset"].get_to(p->en_conv_offset); - j["en_fund_images"].get_to(p->en_fund_images); - j["en_quad_errors"].get_to(p->en_quad_errors); - j["clk_as_noise"].get_to(p->clk_as_noise); - j["dc_as_dist"].get_to(p->dc_as_dist); - j["ilv_as_noise"].get_to(p->ilv_as_noise); - p->set_analysis_band(j["ab_center"].get(), j["ab_width"].get()); - p->set_fdata(j["fdata"].get()); - p->set_fsample(j["fsample"].get()); - p->set_fshift(j["fshift"].get()); - p->set_hd(j["hd"].get()); - p->set_imd(j["imd"].get()); - p->set_wo(j["wo"].get()); - p->set_ssb(FASsb::Default, j["ssb_def"].get()); - p->set_ssb(FASsb::DC , j["ssb_dc" ].get()); - p->set_ssb(FASsb::Signal , j["ssb_sig"].get()); - p->set_ssb(FASsb::WO , j["ssb_wo" ].get()); - p->set_clk(j["clk"].get>()); - p->set_ilv(j["ilv"].get>()); - // components - for (const json& jcomp : j["user_comps"]) { - str_t key = jcomp["key"].get(); - str_t type_str = jcomp["type"].get(); - str_t tag_str = jcomp["tag"].get(); - switch (static_cast(fa_comp_type_map.at(type_str))) - { - case FACompType::FixedTone : { - FACompTag tag = static_cast(fa_comp_tag_map.at(tag_str)); - str_t freq = jcomp["freq"].get(); - int ssb = jcomp["ssb"].get(); - p->add_fixed_tone(key, tag, freq, ssb); - break; - } - case FACompType::MaxTone : { - FACompTag tag = static_cast(fa_comp_tag_map.at(tag_str)); - int ssb = jcomp["ssb"].get(); - p->add_max_tone(key, tag, "0", "fdata", ssb); - break; - } - default: - throw std::exception(); - } - } - // variables - var_map vars; - j["user_vars"].get_to(vars); - for (const var_map::value_type& kv : vars) { - p->set_var(kv.first, kv.second); - } - return p; - } catch (const std::exception&) { - throw runtime_error("error loading fourier_analysis object from file '" + filename + "'"); - } - } +std::shared_ptr fourier_analysis::load(const str_t &filename) { + std::ifstream ifs(filename); + if (!ifs.is_open()) { + throw runtime_error("unable to open file '" + filename + "'"); + } + try { + json j; + ifs >> j; // error handling? + std::shared_ptr p = + std::make_shared(); + j["en_conv_offset"].get_to(p->en_conv_offset); + j["en_fund_images"].get_to(p->en_fund_images); + j["en_quad_errors"].get_to(p->en_quad_errors); + j["clk_as_noise"].get_to(p->clk_as_noise); + j["dc_as_dist"].get_to(p->dc_as_dist); + j["ilv_as_noise"].get_to(p->ilv_as_noise); + p->set_analysis_band(j["ab_center"].get(), + j["ab_width"].get()); + p->set_fdata(j["fdata"].get()); + p->set_fsample(j["fsample"].get()); + p->set_fshift(j["fshift"].get()); + p->set_hd(j["hd"].get()); + p->set_imd(j["imd"].get()); + p->set_wo(j["wo"].get()); + p->set_ssb(FASsb::Default, j["ssb_def"].get()); + p->set_ssb(FASsb::DC, j["ssb_dc"].get()); + p->set_ssb(FASsb::Signal, j["ssb_sig"].get()); + p->set_ssb(FASsb::WO, j["ssb_wo"].get()); + p->set_clk(j["clk"].get>()); + p->set_ilv(j["ilv"].get>()); + // components + for (const json &jcomp : j["user_comps"]) { + str_t key = jcomp["key"].get(); + str_t type_str = jcomp["type"].get(); + str_t tag_str = jcomp["tag"].get(); + switch (static_cast( + fa_comp_type_map.at(type_str))) { + case FACompType::FixedTone: { + FACompTag tag = static_cast( + fa_comp_tag_map.at(tag_str)); + str_t freq = jcomp["freq"].get(); + int ssb = jcomp["ssb"].get(); + p->add_fixed_tone(key, tag, freq, ssb); + break; + } + case FACompType::MaxTone: { + FACompTag tag = static_cast( + fa_comp_tag_map.at(tag_str)); + int ssb = jcomp["ssb"].get(); + p->add_max_tone(key, tag, "0", "fdata", ssb); + break; + } + default: + throw std::exception(); + } + } + // variables + var_map vars; + j["user_vars"].get_to(vars); + for (const var_map::value_type &kv : vars) { + p->set_var(kv.first, kv.second); + } + return p; + } catch (const std::exception &) { + throw runtime_error( + "error loading fourier_analysis object from file '" + + filename + "'"); + } +} - void fourier_analysis::save_impl(const str_t& filename) const - { - std::ofstream ofs (filename); - if (!ofs.is_open()) { - throw runtime_error("Unable to open file '" + filename + "'"); - } - json jcomps; - for (const str_t& key : m_user_keys) { - const fourier_analysis_component& comp = *m_user_comps.at(key); - switch (comp.type) - { - case FACompType::FixedTone : { - auto c = static_cast(comp); - jcomps.push_back(json { - {"freq" , c.freq}, - {"key" , key}, - {"ssb" , c.ssb}, - {"tag" , fa_comp_tag_map.at(to_int(c.tag))}, - {"type" , fa_comp_type_map.at(to_int(c.type))}}); - break; - } - case FACompType::MaxTone : { - auto c = static_cast(comp); - jcomps.push_back(json { - {"key" , key}, - {"ssb" , c.ssb}, - {"tag" , fa_comp_tag_map.at(to_int(c.tag))}, - {"type" , fa_comp_type_map.at(to_int(c.type))}}); - break; - } - default : - continue; - } - } - json j; - j["ab_center"] = m_ab_center; - j["ab_width"] = m_ab_width; - j["clk"] = m_clk; - j["clk_as_noise"] = clk_as_noise; - j["dc_as_dist"] = dc_as_dist; - j["en_conv_offset"] = en_conv_offset; - j["en_fund_images"] = en_fund_images; - j["en_quad_errors"] = en_quad_errors; - j["fdata"] = m_fdata; - j["fsample"] = m_fsample; - j["fshift"] = m_fshift; - j["hd"] = m_hd; - j["ilv"] = m_ilv; - j["ilv_as_noise"] = ilv_as_noise; - j["imd"] = m_imd; - j["ssb_dc"] = m_ssb_dc; - j["ssb_def"] = m_ssb_def; - j["ssb_sig"] = m_ssb_sig; - j["ssb_wo"] = m_ssb_wo; - j["user_comps"] = jcomps; - j["user_vars"] = m_user_vars; - j["version"] = version_string(); - j["wo"] = m_wo; - ofs << std::setw(4) << j << std::endl; - } +void fourier_analysis::save_impl(const str_t &filename) const { + std::ofstream ofs(filename); + if (!ofs.is_open()) { + throw runtime_error("Unable to open file '" + filename + "'"); + } + json jcomps; + for (const str_t &key : m_user_keys) { + const fourier_analysis_component &comp = *m_user_comps.at(key); + switch (comp.type) { + case FACompType::FixedTone: { + auto c = static_cast(comp); + jcomps.push_back(json{ + { "freq", c.freq }, + { "key", key }, + { "ssb", c.ssb }, + { "tag", fa_comp_tag_map.at(to_int(c.tag)) }, + { "type", + fa_comp_type_map.at(to_int(c.type)) } }); + break; + } + case FACompType::MaxTone: { + auto c = static_cast(comp); + jcomps.push_back(json{ + { "key", key }, + { "ssb", c.ssb }, + { "tag", fa_comp_tag_map.at(to_int(c.tag)) }, + { "type", + fa_comp_type_map.at(to_int(c.type)) } }); + break; + } + default: + continue; + } + } + json j; + j["ab_center"] = m_ab_center; + j["ab_width"] = m_ab_width; + j["clk"] = m_clk; + j["clk_as_noise"] = clk_as_noise; + j["dc_as_dist"] = dc_as_dist; + j["en_conv_offset"] = en_conv_offset; + j["en_fund_images"] = en_fund_images; + j["en_quad_errors"] = en_quad_errors; + j["fdata"] = m_fdata; + j["fsample"] = m_fsample; + j["fshift"] = m_fshift; + j["hd"] = m_hd; + j["ilv"] = m_ilv; + j["ilv_as_noise"] = ilv_as_noise; + j["imd"] = m_imd; + j["ssb_dc"] = m_ssb_dc; + j["ssb_def"] = m_ssb_def; + j["ssb_sig"] = m_ssb_sig; + j["ssb_wo"] = m_ssb_wo; + j["user_comps"] = jcomps; + j["user_vars"] = m_user_vars; + j["version"] = version_string(); + j["wo"] = m_wo; + ofs << std::setw(4) << j << std::endl; +} } // namespace genalyzer_impl \ No newline at end of file diff --git a/src/manager.cpp b/src/manager.cpp index cdd1919..4a4e3d1 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #include "manager.hpp" #include "enum_maps.hpp" @@ -10,115 +13,107 @@ namespace genalyzer_impl::manager { - static std::map object_map; - - void clear() - { - object_map.clear(); - } - - bool equal(const str_t& key1, const str_t& key2) - { - contains(key1, true); - contains(key2, true); - const object& obj1 = *object_map.at(key1); - const object& obj2 = *object_map.at(key2); - return obj1.equals(obj2); - } - - bool contains(const str_t& key, bool throw_if_not_found) - { - bool not_found = object_map.end() == object_map.find(key); - if (not_found && throw_if_not_found) { - throw runtime_error("manager::contains : key '" + key + "' not found"); - } - return !not_found; - } - - void remove(const str_t& key) - { - object_map.erase(key); - } - - str_t save(const str_t& key, const str_t& filename) - { - contains(key, true); - str_t fn = get_filename_from_object_key(key, filename); - object_map.at(key)->save(fn); - return fn; - } - - size_t size() - { - return object_map.size(); - } - - str_t to_string(const str_t& key) - { - if (contains(key)) { - return object_map.at(key)->to_string(); - } else { - std::vector header { {"Key", object_type_map.name()} }; - std::vector rows; - for (const auto& kv : object_map) { - const str_t& obj_key = kv.first; - ObjectType obj_type = object_map.at(obj_key)->object_type(); - rows.push_back( {obj_key, object_type_map.at(to_int(obj_type))} ); - } - return table(header, rows, 2, true, true); - } - } - - str_t type_str(const str_t& key) - { - return object_type_map.at(to_int(type(key))); - } - -} // namespace genalyzer::manager +static std::map object_map; + +void clear() { + object_map.clear(); +} + +bool equal(const str_t &key1, const str_t &key2) { + contains(key1, true); + contains(key2, true); + const object &obj1 = *object_map.at(key1); + const object &obj2 = *object_map.at(key2); + return obj1.equals(obj2); +} + +bool contains(const str_t &key, bool throw_if_not_found) { + bool not_found = object_map.end() == object_map.find(key); + if (not_found && throw_if_not_found) { + throw runtime_error("manager::contains : key '" + key + + "' not found"); + } + return !not_found; +} + +void remove(const str_t &key) { + object_map.erase(key); +} + +str_t save(const str_t &key, const str_t &filename) { + contains(key, true); + str_t fn = get_filename_from_object_key(key, filename); + object_map.at(key)->save(fn); + return fn; +} + +size_t size() { + return object_map.size(); +} + +str_t to_string(const str_t &key) { + if (contains(key)) { + return object_map.at(key)->to_string(); + } else { + std::vector header{ { "Key", + object_type_map.name() } }; + std::vector rows; + for (const auto &kv : object_map) { + const str_t &obj_key = kv.first; + ObjectType obj_type = + object_map.at(obj_key)->object_type(); + rows.push_back({ obj_key, object_type_map.at(to_int(obj_type)) }); + } + return table(header, rows, 2, true, true); + } +} + +str_t type_str(const str_t &key) { + return object_type_map.at(to_int(type(key))); +} + +} // namespace genalyzer_impl::manager namespace genalyzer_impl::manager { - void add_object(const str_t& key, object::pointer obj, bool replace) - { - if (!std::regex_match(key, std::regex(key_pattern))) { - throw runtime_error("manager::add_object : invalid key"); - } - if (!obj) { - throw runtime_error("manager::add_object : object is null"); - } - if (contains(key)) { - if (replace) { - object_map.erase(key); - } else { - throw runtime_error("manager::add_object : key already exists"); - } - } - object_map.insert({key, std::move(obj)}); - } - - str_t get_filename_from_object_key(const str_t& key, str_t filename) - { - static const std::regex json_ext_pat {".+[.]json$", std::regex::icase}; - if (filename.empty()) { - filename = key; - } - if (!std::regex_match(filename, json_ext_pat)) { - filename += ".json"; - } - return filename; - } - - object::pointer get_object(const str_t& key) - { - contains(key, true); - object::pointer obj = object_map.at(key); - return obj; - } - - ObjectType type(const str_t& key) - { - contains(key, true); - return object_map.at(key)->object_type(); - } - -} // namespace genalyzer::manager \ No newline at end of file +void add_object(const str_t &key, object::pointer obj, bool replace) { + if (!std::regex_match(key, std::regex(key_pattern))) { + throw runtime_error("manager::add_object : invalid key"); + } + if (!obj) { + throw runtime_error("manager::add_object : object is null"); + } + if (contains(key)) { + if (replace) { + object_map.erase(key); + } else { + throw runtime_error( + "manager::add_object : key already exists"); + } + } + object_map.insert({ key, std::move(obj) }); +} + +str_t get_filename_from_object_key(const str_t &key, str_t filename) { + static const std::regex json_ext_pat{ ".+[.]json$", std::regex::icase }; + if (filename.empty()) { + filename = key; + } + if (!std::regex_match(filename, json_ext_pat)) { + filename += ".json"; + } + return filename; +} + +object::pointer get_object(const str_t &key) { + contains(key, true); + object::pointer obj = object_map.at(key); + return obj; +} + +ObjectType type(const str_t &key) { + contains(key, true); + return object_map.at(key)->object_type(); +} + +} // namespace genalyzer_impl::manager \ No newline at end of file diff --git a/src/platform.cpp b/src/platform.cpp index 43145be..413d3c3 100644 --- a/src/platform.cpp +++ b/src/platform.cpp @@ -1,16 +1,19 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #include "type_aliases.hpp" namespace genalyzer_impl { - static_assert(sizeof(int16_t) == 2, "sizeof(int16_t) != 2"); - static_assert(sizeof(int32_t) == 4, "sizeof(int32_t) != 4"); - static_assert(sizeof(int64_t) == 8, "sizeof(int64_t) != 8"); - static_assert(sizeof(uint16_t) == 2, "sizeof(uint16_t) != 2"); - static_assert(sizeof(uint32_t) == 4, "sizeof(uint32_t) != 4"); - static_assert(sizeof(uint64_t) == 8, "sizeof(uint64_t) != 8"); - static_assert(sizeof(real_t) == 8, "sizeof(real_t) != 8"); - static_assert(sizeof(cplx_t) == 16, "sizeof(cplx_t) != 16"); +static_assert(sizeof(int16_t) == 2, "sizeof(int16_t) != 2"); +static_assert(sizeof(int32_t) == 4, "sizeof(int32_t) != 4"); +static_assert(sizeof(int64_t) == 8, "sizeof(int64_t) != 8"); +static_assert(sizeof(uint16_t) == 2, "sizeof(uint16_t) != 2"); +static_assert(sizeof(uint32_t) == 4, "sizeof(uint32_t) != 4"); +static_assert(sizeof(uint64_t) == 8, "sizeof(uint64_t) != 8"); +static_assert(sizeof(real_t) == 8, "sizeof(real_t) != 8"); +static_assert(sizeof(cplx_t) == 16, "sizeof(cplx_t) != 16"); - static_assert(sizeof(int) >= 4, "sizeof(int) < 4"); +static_assert(sizeof(int) >= 4, "sizeof(int) < 4"); } // namespace genalyzer_impl \ No newline at end of file diff --git a/src/processes.cpp b/src/processes.cpp index 89d847a..5d3dd3c 100644 --- a/src/processes.cpp +++ b/src/processes.cpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #include "processes.hpp" #include "constants.hpp" @@ -11,287 +14,263 @@ #include namespace genalyzer_impl { - - template - void downsample( - const T* in_data, - size_t in_size, - T* out_data, - size_t out_size, - int ratio, - bool interleaved - ) - { - check_array("", "input array", in_data, in_size); - check_array("", "output array", out_data, out_size); - size_t out_size_expected = downsample_size(in_size, ratio, interleaved); - assert_eq("", "output array size", out_size, "expected", out_size_expected); - size_t i = 0; - if (interleaved) { - // check for even in_size ?? - const size_t jump = ratio * 2; - for (size_t j = 0; j < out_size; ++j) { - out_data[j] = in_data[i]; - ++j; - out_data[j] = in_data[i + 1]; - i += jump; - } - } else { - for (size_t j = 0; j < out_size; ++j) { - out_data[j] = in_data[i]; - i += ratio; - } - } - } - template void downsample(const real_t* , size_t, real_t* , size_t, int, bool); - template void downsample(const int16_t*, size_t, int16_t*, size_t, int, bool); - template void downsample(const int32_t*, size_t, int32_t*, size_t, int, bool); - template void downsample(const int64_t*, size_t, int64_t*, size_t, int, bool); - - size_t downsample_size(size_t in_size, int ratio, bool interleaved) - { - assert_gt0("", "downsample ratio", ratio); - size_t out_size = 0; - if (interleaved) { - if (is_odd(in_size)) { - throw runtime_error("size of interleaved array must be even"); - } - in_size /= 2; - out_size = in_size / ratio; - if (0 < in_size % ratio) { - out_size += 1; - } - out_size *= 2; - } else { - out_size = in_size / ratio; - if (0 < in_size % ratio) { - out_size += 1; - } - } - return out_size; - } +template +void downsample(const T *in_data, size_t in_size, T *out_data, size_t out_size, + int ratio, bool interleaved) { + check_array("", "input array", in_data, in_size); + check_array("", "output array", out_data, out_size); + size_t out_size_expected = downsample_size(in_size, ratio, interleaved); + assert_eq("", "output array size", out_size, "expected", + out_size_expected); + size_t i = 0; + if (interleaved) { + // check for even in_size ?? + const size_t jump = ratio * 2; + for (size_t j = 0; j < out_size; ++j) { + out_data[j] = in_data[i]; + ++j; + out_data[j] = in_data[i + 1]; + i += jump; + } + } else { + for (size_t j = 0; j < out_size; ++j) { + out_data[j] = in_data[i]; + i += ratio; + } + } +} - void fshift( - const real_t* i_data, - size_t i_size, - const real_t* q_data, - size_t q_size, - real_t* out_data, - size_t out_size, - real_t fs, - real_t _fshift - ) - { - assert_gt0("", "fs", fs); - _fshift -= std::floor(_fshift / fs) * fs; // [0, fs) - const real_t twopix = k_2pi * _fshift / fs; - if (0 == q_size) { - // Interleaved I/Q - check_array_pair("", "input array", i_data, i_size, "output array", out_data, out_size, true); - const size_t size = i_size / 2; - const cplx_t* pin = reinterpret_cast(i_data); - cplx_t* pout = reinterpret_cast(out_data); - const cplx_t jtwopix = {0.0, twopix}; - cplx_t jtwopix_n = 0.0; - for (size_t i = 0; i < size; ++i) { - pout[i] = pin[i] * std::exp(jtwopix_n); - jtwopix_n += jtwopix; - } - } else { - // Split I/Q - check_array_pair("", "I array", i_data, i_size, "Q array", q_data, q_size); - check_array("", "output array", out_data, out_size); - assert_eq("", "output array size", out_size, "expected", i_size * 2); - real_t twopix_n = 0.0; - for (size_t i = 0, j = 0; i < i_size; ++i, j += 2) { - real_t x = std::cos(twopix_n); - real_t y = std::sin(twopix_n); - out_data[j] = i_data[i] * x - q_data[i] * y; - out_data[j+1] = i_data[i] * y + q_data[i] * x; - twopix_n += twopix; - } - } - } +template void downsample(const real_t *, size_t, real_t *, size_t, int, bool); +template void downsample(const int16_t *, size_t, int16_t *, size_t, int, bool); +template void downsample(const int32_t *, size_t, int32_t *, size_t, int, bool); +template void downsample(const int64_t *, size_t, int64_t *, size_t, int, bool); - template - void fshift( - const T* i_data, - size_t i_size, - const T* q_data, - size_t q_size, - T* out_data, - size_t out_size, - int n, - real_t fs, - real_t _fshift, - CodeFormat format - ) - { - resolution_to_minmax(n, format); - assert_gt0("", "fs", fs); - _fshift -= std::floor(_fshift / fs) * fs; // [0, fs) - const real_t twopix = k_2pi * _fshift / fs; - size_t in_stride = 0; - if (0 == q_size) { - // Interleaved I/Q - check_array("", "input array", i_data, i_size, true); - i_size /= 2; - q_size = i_size; - q_data = i_data + 1; - in_stride = 2; - } else { - // Split I/Q - check_array_pair("", "I array", i_data, i_size, "Q array", q_data, q_size); - in_stride = 1; - } - check_array("", "output array", out_data, out_size); - assert_eq("", "output array size", out_size, "expected", i_size + q_size); - real_t twopix_n = 0.0; - const real_t min_code = -std::pow(2.0, n - 1); - const real_t max_code = -1.0 - min_code; - const real_t os = (CodeFormat::OffsetBinary == format) ? -min_code : 0.0; - for (size_t i = 0, j = 0; j < out_size; i += in_stride, j += 2) { - real_t x = std::cos(twopix_n); - real_t y = std::sin(twopix_n); - real_t itmp1 = static_cast(i_data[i]) - os; - real_t qtmp1 = static_cast(q_data[i]) - os; - real_t itmp2 = std::clamp(std::round(itmp1 * x - qtmp1 * y), min_code, max_code); - real_t qtmp2 = std::clamp(std::round(itmp1 * y + qtmp1 * x), min_code, max_code); - out_data[j] = static_cast(itmp2 + os); - out_data[j+1] = static_cast(qtmp2 + os); - twopix_n += twopix; - } - } - - template void fshift(const int16_t*, size_t, const int16_t*, size_t, int16_t*, size_t, int, real_t, real_t, CodeFormat); - template void fshift(const int32_t*, size_t, const int32_t*, size_t, int32_t*, size_t, int, real_t, real_t, CodeFormat); - template void fshift(const int64_t*, size_t, const int64_t*, size_t, int64_t*, size_t, int, real_t, real_t, CodeFormat); - - size_t fshift_size(size_t i_size, size_t q_size) - { - if (0 == q_size) { - // Input I contains Interleaved I/Q; Input Q is unused - if (is_odd(i_size)) { - throw runtime_error("size of interleaved array must be even"); - } - return i_size; - } else { - // Split I/Q - assert_eq("", "I size", i_size, "Q size", q_size); - return i_size + q_size; - } - } - - template - void normalize( - const T* in_data, - size_t in_size, - real_t* out_data, - size_t out_size, - int n, - CodeFormat format - ) - { - check_array_pair("normalize : ", "input array", in_data, in_size, "output array", out_data, out_size); - check_code_width("normalize : ", n); - const real_t scalar = 2.0 / (1 << n); - if (CodeFormat::OffsetBinary == format) { - for (size_t i = 0; i < out_size; ++i) { - out_data[i] = std::fma(scalar, static_cast(in_data[i]), -1.0); - } - } else { - for (size_t i = 0; i < out_size; ++i) { - out_data[i] = scalar * static_cast(in_data[i]); - } - } - } +size_t downsample_size(size_t in_size, int ratio, bool interleaved) { + assert_gt0("", "downsample ratio", ratio); + size_t out_size = 0; + if (interleaved) { + if (is_odd(in_size)) { + throw runtime_error( + "size of interleaved array must be even"); + } + in_size /= 2; + out_size = in_size / ratio; + if (0 < in_size % ratio) { + out_size += 1; + } + out_size *= 2; + } else { + out_size = in_size / ratio; + if (0 < in_size % ratio) { + out_size += 1; + } + } + return out_size; +} - template void normalize(const int16_t*, size_t, real_t*, size_t, int, CodeFormat); - template void normalize(const int32_t*, size_t, real_t*, size_t, int, CodeFormat); - template void normalize(const int64_t*, size_t, real_t*, size_t, int, CodeFormat); - - void polyval( - const real_t* in_data, - size_t in_size, - real_t* out_data, - size_t out_size, - const real_t* c_data, - size_t c_size - ) - { - check_array_pair("polyval : ", "input array", in_data, in_size, "output array", out_data, out_size); - check_array("polyval : ", "coefficient array", c_data, c_size); - std::vector c (c_data, c_data + c_size); - while (1 < c.size() && 0.0 == c.back()) { - c.pop_back(); - } - const real_t last_c = c.back(); - c.pop_back(); - if (c.empty()) { - // y = c0 - std::fill(out_data, out_data + out_size, last_c); - } else if (1 == c.size()) { - // y = c1 * x + c0 - const real_t c0 = c[0]; - for (size_t i = 0; i < out_size; ++i) { - out_data[i] = std::fma(last_c, in_data[i], c0); - } - } else { - std::reverse(c.begin(), c.end()); - // Horner's method - // 3rd degree example: - // y = x * (x * (x * c3 + c2) + c1) + c0 - for (size_t i = 0; i < out_size; ++i) { - real_t tmp = last_c; - for (real_t cn : c) { - tmp = std::fma(in_data[i], tmp, cn); - } - out_data[i] = tmp; - } - } - } +void fshift(const real_t *i_data, size_t i_size, const real_t *q_data, + size_t q_size, real_t *out_data, size_t out_size, real_t fs, + real_t _fshift) { + assert_gt0("", "fs", fs); + _fshift -= std::floor(_fshift / fs) * fs; // [0, fs) + const real_t twopix = k_2pi * _fshift / fs; + if (0 == q_size) { + // Interleaved I/Q + check_array_pair("", "input array", i_data, i_size, + "output array", out_data, out_size, true); + const size_t size = i_size / 2; + const cplx_t *pin = reinterpret_cast(i_data); + cplx_t *pout = reinterpret_cast(out_data); + const cplx_t jtwopix = { 0.0, twopix }; + cplx_t jtwopix_n = 0.0; + for (size_t i = 0; i < size; ++i) { + pout[i] = pin[i] * std::exp(jtwopix_n); + jtwopix_n += jtwopix; + } + } else { + // Split I/Q + check_array_pair("", "I array", i_data, i_size, "Q array", + q_data, q_size); + check_array("", "output array", out_data, out_size); + assert_eq("", "output array size", out_size, "expected", + i_size * 2); + real_t twopix_n = 0.0; + for (size_t i = 0, j = 0; i < i_size; ++i, j += 2) { + real_t x = std::cos(twopix_n); + real_t y = std::sin(twopix_n); + out_data[j] = i_data[i] * x - q_data[i] * y; + out_data[j + 1] = i_data[i] * y + q_data[i] * x; + twopix_n += twopix; + } + } +} - template - void quantize( - const real_t* in_data, - size_t in_size, - T* out_data, - size_t out_size, - real_t fsr, - int n, - real_t noise, - CodeFormat format - ) - { - const char* trace = "quantize : "; - check_array_pair(trace, "input array", in_data, in_size, "output array", out_data, out_size); - assert_gt0(trace, "fsr", fsr); - resolution_to_minmax(n, format); - const real_t lsb = fsr / (1 << n); - const real_t min_code = -std::pow(2.0, n - 1); - const real_t max_code = -1.0 - min_code; - const real_t os = (CodeFormat::OffsetBinary == format) ? -min_code : 0.0; - if (0.0 == noise) { - for (size_t i = 0; i < out_size; ++i) { - real_t c = std::floor(in_data[i] / lsb); - c = std::clamp(c, min_code, max_code); - out_data[i] = static_cast(c + os); - } - } else { - std::random_device rdev; - std::mt19937 rgen (rdev()); - auto ngen = std::bind(std::normal_distribution(0.0, std::fabs(noise)), rgen); - for (size_t i = 0; i < out_size; ++i) { - real_t c = std::floor((in_data[i] + ngen()) / lsb); - c = std::clamp(c, min_code, max_code); - out_data[i] = static_cast(c + os); - } - } - } +template +void fshift(const T *i_data, size_t i_size, const T *q_data, size_t q_size, + T *out_data, size_t out_size, int n, real_t fs, real_t _fshift, + CodeFormat format) { + resolution_to_minmax(n, format); + assert_gt0("", "fs", fs); + _fshift -= std::floor(_fshift / fs) * fs; // [0, fs) + const real_t twopix = k_2pi * _fshift / fs; + size_t in_stride = 0; + if (0 == q_size) { + // Interleaved I/Q + check_array("", "input array", i_data, i_size, true); + i_size /= 2; + q_size = i_size; + q_data = i_data + 1; + in_stride = 2; + } else { + // Split I/Q + check_array_pair("", "I array", i_data, i_size, "Q array", + q_data, q_size); + in_stride = 1; + } + check_array("", "output array", out_data, out_size); + assert_eq("", "output array size", out_size, "expected", + i_size + q_size); + real_t twopix_n = 0.0; + const real_t min_code = -std::pow(2.0, n - 1); + const real_t max_code = -1.0 - min_code; + const real_t os = (CodeFormat::OffsetBinary == format) ? -min_code : 0.0; + for (size_t i = 0, j = 0; j < out_size; i += in_stride, j += 2) { + real_t x = std::cos(twopix_n); + real_t y = std::sin(twopix_n); + real_t itmp1 = static_cast(i_data[i]) - os; + real_t qtmp1 = static_cast(q_data[i]) - os; + real_t itmp2 = std::clamp(std::round(itmp1 * x - qtmp1 * y), + min_code, max_code); + real_t qtmp2 = std::clamp(std::round(itmp1 * y + qtmp1 * x), + min_code, max_code); + out_data[j] = static_cast(itmp2 + os); + out_data[j + 1] = static_cast(qtmp2 + os); + twopix_n += twopix; + } +} - template void quantize(const real_t*, size_t, int16_t*, size_t, real_t, int, real_t, CodeFormat); - template void quantize(const real_t*, size_t, int32_t*, size_t, real_t, int, real_t, CodeFormat); - template void quantize(const real_t*, size_t, int64_t*, size_t, real_t, int, real_t, CodeFormat); +template void fshift(const int16_t *, size_t, const int16_t *, size_t, + int16_t *, size_t, int, real_t, real_t, CodeFormat); +template void fshift(const int32_t *, size_t, const int32_t *, size_t, + int32_t *, size_t, int, real_t, real_t, CodeFormat); +template void fshift(const int64_t *, size_t, const int64_t *, size_t, + int64_t *, size_t, int, real_t, real_t, CodeFormat); + +size_t fshift_size(size_t i_size, size_t q_size) { + if (0 == q_size) { + // Input I contains Interleaved I/Q; Input Q is unused + if (is_odd(i_size)) { + throw runtime_error( + "size of interleaved array must be even"); + } + return i_size; + } else { + // Split I/Q + assert_eq("", "I size", i_size, "Q size", q_size); + return i_size + q_size; + } +} + +template +void normalize(const T *in_data, size_t in_size, real_t *out_data, + size_t out_size, int n, CodeFormat format) { + check_array_pair("normalize : ", "input array", in_data, in_size, + "output array", out_data, out_size); + check_code_width("normalize : ", n); + const real_t scalar = 2.0 / (1 << n); + if (CodeFormat::OffsetBinary == format) { + for (size_t i = 0; i < out_size; ++i) { + out_data[i] = std::fma( + scalar, static_cast(in_data[i]), -1.0); + } + } else { + for (size_t i = 0; i < out_size; ++i) { + out_data[i] = scalar * static_cast(in_data[i]); + } + } +} + +template void normalize(const int16_t *, size_t, real_t *, size_t, int, + CodeFormat); +template void normalize(const int32_t *, size_t, real_t *, size_t, int, + CodeFormat); +template void normalize(const int64_t *, size_t, real_t *, size_t, int, + CodeFormat); + +void polyval(const real_t *in_data, size_t in_size, real_t *out_data, + size_t out_size, const real_t *c_data, size_t c_size) { + check_array_pair("polyval : ", "input array", in_data, in_size, + "output array", out_data, out_size); + check_array("polyval : ", "coefficient array", c_data, c_size); + std::vector c(c_data, c_data + c_size); + while (1 < c.size() && 0.0 == c.back()) { + c.pop_back(); + } + const real_t last_c = c.back(); + c.pop_back(); + if (c.empty()) { + // y = c0 + std::fill(out_data, out_data + out_size, last_c); + } else if (1 == c.size()) { + // y = c1 * x + c0 + const real_t c0 = c[0]; + for (size_t i = 0; i < out_size; ++i) { + out_data[i] = std::fma(last_c, in_data[i], c0); + } + } else { + std::reverse(c.begin(), c.end()); + // Horner's method + // 3rd degree example: + // y = x * (x * (x * c3 + c2) + c1) + c0 + for (size_t i = 0; i < out_size; ++i) { + real_t tmp = last_c; + for (real_t cn : c) { + tmp = std::fma(in_data[i], tmp, cn); + } + out_data[i] = tmp; + } + } +} + +template +void quantize(const real_t *in_data, size_t in_size, T *out_data, + size_t out_size, real_t fsr, int n, real_t noise, + CodeFormat format) { + const char *trace = "quantize : "; + check_array_pair(trace, "input array", in_data, in_size, "output array", + out_data, out_size); + assert_gt0(trace, "fsr", fsr); + resolution_to_minmax(n, format); + const real_t lsb = fsr / (1 << n); + const real_t min_code = -std::pow(2.0, n - 1); + const real_t max_code = -1.0 - min_code; + const real_t os = (CodeFormat::OffsetBinary == format) ? -min_code : 0.0; + if (0.0 == noise) { + for (size_t i = 0; i < out_size; ++i) { + real_t c = std::floor(in_data[i] / lsb); + c = std::clamp(c, min_code, max_code); + out_data[i] = static_cast(c + os); + } + } else { + std::random_device rdev; + std::mt19937 rgen(rdev()); + auto ngen = std::bind( + std::normal_distribution(0.0, std::fabs(noise)), + rgen); + for (size_t i = 0; i < out_size; ++i) { + real_t c = std::floor((in_data[i] + ngen()) / lsb); + c = std::clamp(c, min_code, max_code); + out_data[i] = static_cast(c + os); + } + } +} + +template void quantize(const real_t *, size_t, int16_t *, size_t, real_t, int, + real_t, CodeFormat); +template void quantize(const real_t *, size_t, int32_t *, size_t, real_t, int, + real_t, CodeFormat); +template void quantize(const real_t *, size_t, int64_t *, size_t, real_t, int, + real_t, CodeFormat); } // namespace genalyzer_impl \ No newline at end of file diff --git a/src/utils.cpp b/src/utils.cpp index 2ecf4e2..d19f0be 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #include "utils.hpp" #include @@ -7,51 +10,51 @@ namespace genalyzer_impl { - str_t to_string(real_t n, FPFormat fmt, int max_prec) - { - if (!std::isfinite(n)) { - throw runtime_error("to_string : non-finite number"); - } - int max_digits10 = std::numeric_limits::max_digits10; - if (max_prec < 0 || max_digits10 < max_prec) { - max_prec = max_digits10; - } - std::ostringstream ss; - ss.precision(max_prec); - switch (fmt) - { - case FPFormat::Auto : - ss << std::defaultfloat << n; - break; - case FPFormat::Eng : { - bool neg = std::signbit(n); - n = std::fabs(n); - real_t exp3 = 0; - if (0.0 < n) { - exp3 = std::floor(std::log10(n) / 3) * 3; // snap exponent to nearest multiple of 3 - } - if (exp3 < -3 || 0 < exp3) { - n *= std::pow(10.0, -exp3); - } - if (neg) { - ss << '-'; - } - ss << std::defaultfloat << n; - if (exp3 < -3 || 0 < exp3) { - ss << 'e' << exp3; - } - break; - } - case FPFormat::Fix : - ss << std::fixed << n; - break; - case FPFormat::Sci : - ss << std::scientific << n; - break; - default: - throw runtime_error("to_string : unknown floating point format"); - } - return ss.str(); - } +str_t to_string(real_t n, FPFormat fmt, int max_prec) { + if (!std::isfinite(n)) { + throw runtime_error("to_string : non-finite number"); + } + int max_digits10 = std::numeric_limits::max_digits10; + if (max_prec < 0 || max_digits10 < max_prec) { + max_prec = max_digits10; + } + std::ostringstream ss; + ss.precision(max_prec); + switch (fmt) { + case FPFormat::Auto: + ss << std::defaultfloat << n; + break; + case FPFormat::Eng: { + bool neg = std::signbit(n); + n = std::fabs(n); + real_t exp3 = 0; + if (0.0 < n) { + exp3 = std::floor(std::log10(n) / 3) * + 3; // snap exponent to nearest multiple of 3 + } + if (exp3 < -3 || 0 < exp3) { + n *= std::pow(10.0, -exp3); + } + if (neg) { + ss << '-'; + } + ss << std::defaultfloat << n; + if (exp3 < -3 || 0 < exp3) { + ss << 'e' << exp3; + } + break; + } + case FPFormat::Fix: + ss << std::fixed << n; + break; + case FPFormat::Sci: + ss << std::scientific << n; + break; + default: + throw runtime_error( + "to_string : unknown floating point format"); + } + return ss.str(); +} } // namespace genalyzer_impl \ No newline at end of file diff --git a/src/version.cpp b/src/version.cpp index 4979ef1..ca5155e 100644 --- a/src/version.cpp +++ b/src/version.cpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #include "version.hpp" #include @@ -7,13 +10,10 @@ namespace genalyzer_impl { - std::string_view version_string() - { - static const char* s = - MACRO_TO_STRING(GENALYZER_VERSION_MAJOR) "." - MACRO_TO_STRING(GENALYZER_VERSION_MINOR) "." - MACRO_TO_STRING(GENALYZER_VERSION_PATCH); - return s; - } +std::string_view version_string() { + static const char *s = MACRO_TO_STRING(GENALYZER_VERSION_MAJOR) "." MACRO_TO_STRING( + GENALYZER_VERSION_MINOR) "." MACRO_TO_STRING(GENALYZER_VERSION_PATCH); + return s; +} } // namespace genalyzer_impl \ No newline at end of file diff --git a/src/waveforms.cpp b/src/waveforms.cpp index ece3f2a..a9a881f 100644 --- a/src/waveforms.cpp +++ b/src/waveforms.cpp @@ -1,3 +1,6 @@ +// Copyright (C) 2024 Analog Devices, Inc. +// +// SPDX short identifier: ADIBSD OR GPL-2.0-or-later #include "waveforms.hpp" #include "constants.hpp" @@ -10,154 +13,122 @@ namespace genalyzer_impl { - namespace { +namespace { - void sinusoid( - double(*func)(double), - real_t* data, - size_t size, - real_t fs, - real_t ampl, - real_t freq, - real_t phase, - real_t td, - real_t tj - ) - { - check_array("", "output array", data, size); - assert_gt0("", "fs", fs); - const real_t twopif = k_2pi * freq; - const real_t twopifts = twopif / fs; - const real_t twopiftd_plus_phase = std::fma(twopif, td, phase); - real_t theta = twopiftd_plus_phase; - if (0.0 == tj) { - for (size_t i = 0; i < size; ++i) { - data[i] = ampl * func(theta); - theta += twopifts; - } - } else { - std::random_device rdev; - std::mt19937 rgen (rdev()); - auto ngen = std::bind(std::normal_distribution(0.0, twopif * tj), rgen); - for (size_t i = 0; i < size; ++i) { - data[i] = theta + ngen(); - theta += twopifts; - } // breaking into two loops gives modest speed improvement - for (size_t i = 0; i < size; ++i) { - data[i] = ampl * func(data[i]); - } - } - } +void sinusoid(double (*func)(double), real_t *data, size_t size, real_t fs, + real_t ampl, real_t freq, real_t phase, real_t td, real_t tj) { + check_array("", "output array", data, size); + assert_gt0("", "fs", fs); + const real_t twopif = k_2pi * freq; + const real_t twopifts = twopif / fs; + const real_t twopiftd_plus_phase = std::fma(twopif, td, phase); + real_t theta = twopiftd_plus_phase; + if (0.0 == tj) { + for (size_t i = 0; i < size; ++i) { + data[i] = ampl * func(theta); + theta += twopifts; + } + } else { + std::random_device rdev; + std::mt19937 rgen(rdev()); + auto ngen = std::bind( + std::normal_distribution(0.0, twopif * tj), + rgen); + for (size_t i = 0; i < size; ++i) { + data[i] = theta + ngen(); + theta += twopifts; + } // breaking into two loops gives modest speed improvement + for (size_t i = 0; i < size; ++i) { + data[i] = ampl * func(data[i]); + } + } +} - } // namespace anonymous - - void cos( - real_t* data, - size_t size, - real_t fs, - real_t ampl, - real_t freq, - real_t phase, - real_t td, - real_t tj - ) - { - sinusoid(std::cos, data, size, fs, ampl, freq, phase, td, tj); - } - - void gaussian(real_t* data, size_t size, real_t mean, real_t sd) - { - check_array("", "output array", data, size); - if (0.0 == sd) { - for (size_t i = 0; i < size; ++i) { - data[i] = mean; - } - } else { - std::random_device rdev; - std::mt19937 rgen (rdev()); - auto ngen = std::bind(std::normal_distribution(mean, std::fabs(sd)), rgen); - for (size_t i = 0; i < size; ++i) { - data[i] = ngen(); - } - } - } - - void ramp(real_t* data, size_t size, real_t start, real_t stop, real_t noise) - { - check_array("", "output array", data, size); - const real_t step = (stop - start) / static_cast(size); - real_t x = start + step / 2; - if (0.0 == noise) { - for (size_t i = 0; i < size; ++i) { - data[i] = x; - x += step; - } - } else { - std::random_device rdev; - std::mt19937 rgen (rdev()); - auto ngen = std::bind(std::normal_distribution(0.0, std::fabs(noise)), rgen); - for (size_t i = 0; i < size; ++i) { - data[i] = x + ngen(); - x += step; - } - } - } - - void sin( - real_t* data, - size_t size, - real_t fs, - real_t ampl, - real_t freq, - real_t phase, - real_t td, - real_t tj - ) - { - sinusoid(std::sin, data, size, fs, ampl, freq, phase, td, tj); - } - - template - std::map wf_analysis(const T* wf_data, size_t wf_size) - { - check_array("", "waveform array", wf_data, wf_size); - std_reduce_t r = std_reduce(wf_data, wf_size, 0, wf_size); - real_t n = static_cast(wf_size); - real_t avg = r.sum / n; - real_t rms = std::sqrt(r.sumsq / n); - real_t rmsac = std::sqrt(rms * rms - avg * avg); - std::vector keys = wf_analysis_ordered_keys(); - return std::map { - { keys[0] , r.min }, - { keys[1] , r.max }, - { keys[2] , (r.max + r.min) / 2 }, - { keys[3] , r.max - r.min }, - { keys[4] , avg }, - { keys[5] , rms }, - { keys[6] , rmsac }, - { keys[7] , static_cast(r.min_index) }, - { keys[8] , static_cast(r.max_index) }}; - } +} // namespace - template std::map wf_analysis(const int16_t*, size_t); - template std::map wf_analysis(const int32_t*, size_t); - template std::map wf_analysis(const int64_t*, size_t); - template std::map wf_analysis(const real_t*, size_t); +void cos(real_t *data, size_t size, real_t fs, real_t ampl, real_t freq, + real_t phase, real_t td, real_t tj) { + sinusoid(std::cos, data, size, fs, ampl, freq, phase, td, tj); +} - const std::vector& wf_analysis_ordered_keys() - { - static const std::vector keys { - "min", - "max", - "mid", - "range", - "avg", - "rms", - "rmsac", - "min_index", - "max_index" - }; - return keys; - } +void gaussian(real_t *data, size_t size, real_t mean, real_t sd) { + check_array("", "output array", data, size); + if (0.0 == sd) { + for (size_t i = 0; i < size; ++i) { + data[i] = mean; + } + } else { + std::random_device rdev; + std::mt19937 rgen(rdev()); + auto ngen = std::bind( + std::normal_distribution(mean, std::fabs(sd)), + rgen); + for (size_t i = 0; i < size; ++i) { + data[i] = ngen(); + } + } +} + +void ramp(real_t *data, size_t size, real_t start, real_t stop, real_t noise) { + check_array("", "output array", data, size); + const real_t step = (stop - start) / static_cast(size); + real_t x = start + step / 2; + if (0.0 == noise) { + for (size_t i = 0; i < size; ++i) { + data[i] = x; + x += step; + } + } else { + std::random_device rdev; + std::mt19937 rgen(rdev()); + auto ngen = std::bind( + std::normal_distribution(0.0, std::fabs(noise)), + rgen); + for (size_t i = 0; i < size; ++i) { + data[i] = x + ngen(); + x += step; + } + } +} + +void sin(real_t *data, size_t size, real_t fs, real_t ampl, real_t freq, + real_t phase, real_t td, real_t tj) { + sinusoid(std::sin, data, size, fs, ampl, freq, phase, td, tj); +} + +template +std::map wf_analysis(const T *wf_data, size_t wf_size) { + check_array("", "waveform array", wf_data, wf_size); + std_reduce_t r = std_reduce(wf_data, wf_size, 0, wf_size); + real_t n = static_cast(wf_size); + real_t avg = r.sum / n; + real_t rms = std::sqrt(r.sumsq / n); + real_t rmsac = std::sqrt(rms * rms - avg * avg); + std::vector keys = wf_analysis_ordered_keys(); + return std::map{ + { keys[0], r.min }, + { keys[1], r.max }, + { keys[2], (r.max + r.min) / 2 }, + { keys[3], r.max - r.min }, + { keys[4], avg }, + { keys[5], rms }, + { keys[6], rmsac }, + { keys[7], static_cast(r.min_index) }, + { keys[8], static_cast(r.max_index) } + }; +} + +template std::map wf_analysis(const int16_t *, size_t); +template std::map wf_analysis(const int32_t *, size_t); +template std::map wf_analysis(const int64_t *, size_t); +template std::map wf_analysis(const real_t *, size_t); + +const std::vector &wf_analysis_ordered_keys() { + static const std::vector keys{ + "min", "max", "mid", "range", "avg", + "rms", "rmsac", "min_index", "max_index" + }; + return keys; +} } // namespace genalyzer_impl