Skip to content

Commit

Permalink
Add SNR of product of two signals
Browse files Browse the repository at this point in the history
Fixes #341
  • Loading branch information
mhostetter committed May 27, 2024
1 parent 9b6a0c3 commit 58d14ec
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/sdr/_estimation/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""
A subpackage for various estimation algorithms.
"""

from ._snr import *
85 changes: 85 additions & 0 deletions src/sdr/_estimation/_snr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
"""
A module containing estimation algorithms for signal-to-noise ratio (SNR) calculations.
"""

from __future__ import annotations

import numpy as np
import numpy.typing as npt

from .._conversion import db, linear
from .._helper import export


@export
def composite_snr(snr1: npt.ArrayLike, snr2: npt.ArrayLike) -> npt.NDArray[np.float64]:
r"""
Calculates the signal-to-noise ratio (SNR) of the product of two signals.
Arguments:
snr1: The signal-to-noise ratio (SNR) of the first signal $\gamma_1$ in dB.
snr2: The signal-to-noise ratio (SNR) of the second signal $\gamma_2$ in dB.
Returns:
The signal-to-noise ratio (SNR) of the product of the two signals $\gamma$ in dB.
Notes:
$$\frac{1}{\gamma} = \frac{1}{2} \left[ \frac{1}{\gamma_1} + \frac{1}{\gamma_2} + \frac{1}{\gamma_1 \cdot \gamma_2} \right]$$
References:
- `Seymour Stein, Algorithms for Ambiguity Function Processing <https://ieeexplore.ieee.org/document/1163621>`_
Examples:
Calculate the composite SNR of two signals with equal SNRs. Notice for positive input SNR, the composite SNR
is linear with slope 1 and intercept 0 dB. For negative input SNR, the composite SNR is linear with slope 2 and
offset 3 dB.
.. ipython:: python
snr1 = np.linspace(-60, 60, 101)
@savefig sdr_composite_snr_1.png
plt.figure(); \
plt.plot(snr1, sdr.composite_snr(snr1, snr1)); \
plt.xlim(-60, 60); \
plt.ylim(-60, 60); \
plt.xlabel("Input SNRs (dB), $\gamma_1$ and $\gamma_2$"); \
plt.ylabel(r"Composite SNR (dB), $\gamma$"); \
plt.title("Composite SNR of two signals with equal SNRs");
Calculate the composite SNR of two signals with different SNRs. Notice the knee of the curve is located at
`max(0, snr2)`. Left of the knee, the composite SNR is linear with slope 2 and intercept `snr2 + 3` dB.
Right of the knee, the composite SNR is linear with slope 0 and intercept `snr2 + 3` dB.
.. ipython:: python
snr1 = np.linspace(-60, 60, 101)
plt.figure();
for snr2 in np.arange(-40, 40 + 10, 10):
plt.plot(snr1, sdr.composite_snr(snr1, snr2), label=snr2)
@savefig sdr_composite_snr_2.png
plt.legend(title="SNR of signal 2 (dB), $\gamma_2$"); \
plt.xlim(-60, 60); \
plt.ylim(-60, 60); \
plt.xlabel("SNR of signal 1 (dB), $\gamma_1$"); \
plt.ylabel(r"Composite SNR (dB), $\gamma$"); \
plt.title("Composite SNR of two signals with different SNRs");
Group:
estimation-snr
"""
snr1 = np.asarray(snr1)
snr2 = np.asarray(snr2)

# Convert to linear
snr1 = linear(snr1)
snr2 = linear(snr2)

inv_snr = 0.5 * (1 / snr1 + 1 / snr2 + 1 / (snr1 * snr2))
snr = 1 / inv_snr

# Convert to dB
snr = db(snr)

return snr

0 comments on commit 58d14ec

Please sign in to comment.