discuss-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: bug & SNR routine


From: Marcus Müller
Subject: Re: bug & SNR routine
Date: Fri, 4 Nov 2022 11:21:57 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.3.1

Hi George,

> 1) In Log Power FFT documentation 'Create a log10(abs(fft)) stream chain, with real or complex input.' it seems that is missing the ^2.

I think this is [1], right?

In that case, you're right, the block actually calculates the magnitude square. Fixed that! You can do such fixes yourself, by the way: you just need to sign up for a wiki account (had to close down the approval chain for unauthenticated edits to the wiki. Spam sucks.)

> 2) I write a generic SNR routine as a Python block. It seems OK.

What is generic SNR? Such a thing does in general not exist! You're assuming your signal fits into a single FFT bin, so, having sinc spectrum, meaning having gone through a (frequency-shifted) rectangular filter exactly the length of your FFT, and is also perfectly synchronized to the position of a single FFT bin in frequency. That is (almost) surely not the case!
If it's not exactly in the position of an FFT bin, you get leakage. And that means you both underestimate your signal power, and overestimate the noise power. Not a great estimation method, because assuming you don't know the frequency of your signal exactly, you're likely to not hit the right frequency very well, so you don't know by how much you underestimate the SNR.

If I'd want to estimate the SNR and all I know my signal is a narrowband signal (otherwise, there might be better methods), I'd use the PLL Carrier Tracking [2] block, to mix down my narrowband signal to 0 Hz, then use a low-pass filter block on that to really get rid of the things around, then Complex to Mag²[3], then a long Moving Average[4] block to get an average signal power. Do the same Complex to Mag² -> Moving Average on the unprocessed input, subtract the signal power from above to get the noise power. Now you have S and N (in linear terms), so you get your SNR :)

Also, your work method has two bugs:
1. You're not excluding the signal from the noise power calculation; S/N > S/(S+N) !!
2. You're assuming there's always the same number of input items available at the input. That's not the case!


Best regards,
Marcus

[1] https://wiki.gnuradio.org/index.php/Log_Power_FFT
[2] https://wiki.gnuradio.org/index.php?title=PLL_Carrier_Tracking
[3] https://wiki.gnuradio.org/index.php?title=Complex_to_Mag_Squared
[4] https://wiki.gnuradio.org/index.php?title=Moving_Average
On 04.11.22 10:16, George Katsimaglis wrote:
Hello,

1) In Log Power FFT documentation 'Create a log10(abs(fft)) stream chain, with real or complex input.' it seems that is missing the ^2.

2) I write a generic SNR routine as a Python block. It seems OK.


import numpy as np
from gnuradio import gr

class my_snr(gr.decim_block): # decimation = fft_size
    """SNR calculation by George SV1BDS"""

    def __init__(self, fft_size = 1024 ):  # only default arguments here
        """arguments to this function show up as parameters in GRC"""
        gr.decim_block.__init__(
            self,
            name='SNR',   # will show up in GRC
            in_sig=[np.complex64],
            out_sig=[np.float32],
            decim = fft_size
        )
        self.set_relative_rate(1.0/fft_size)
        self.fft_size = fft_size

    def work(self, input_items, output_items):
        """SNR routine"""
        a = np.asarray(input_items[0][:])
        f = np.fft.fft(a)
        x =  10*np.log10(np.real(f*np.conj(f)))
        output_items[0][:] = np.amax(x)-np.mean(x)  
        return 1
          
Is it of general interest to include it in GNURadio ?

Best regards


reply via email to

[Prev in Thread] Current Thread [Next in Thread]