Skip to content
Snippets Groups Projects
range_doppler_widget.py 3.96 KiB
Newer Older
# -*- coding: utf-8 -*-
"""
RangeDoppler Widget Class.
Contains RadarWidget class used to range-Doppler graphs

Author: Jason Merlo
Maintainer: Jason Merlo (merlojas@msu.edu)
"""
import pyqtgraph as pg          # Used for RadarWidget superclass
import numpy as np              # Used for numerical operations
from scipy import signal        # Used for upsampling
import time                     # Used for FPS calculations
from matplotlib import cm       # Used for colormaps


class RangeDopplerWidget(pg.PlotWidget):
    def __init__(self, receiver, xrange=[-50,50], yrange=[-15e3,0]):
        super().__init__()

        # Copy arguments to member variables
        self.daq = receiver.daq
        self.source = self.daq.source
        self.receiver = receiver
        self.update_period = \
            self.source.sample_chunk_size / self.source.sample_rate

        self.xrange = xrange
        self.yrange = yrange

        # FPS ticker data
        self.lastTime = time.time()
        self.fps = None

        # -----

        self.img = pg.ImageItem()
        self.addItem(self.img)

        # Allocate image array to store spectrogram
        # self.img_array = np.zeros(np.around(np.array(self.receiver.fft_mat.shape) / self.downsample).astype(np.int))

        # Get the colormap
        colormap = cm.get_cmap("jet")  # cm.get_cmap("CMRmap")
        colormap._init()
        lut = (colormap._lut * 255).view(np.ndarray)

        # set colormap
        self.img.setLookupTable(lut)
        self.img.setLevels([-50, 20])

        self.setLabel('left', 'Frequency', units='Hz')
        self.setLabel('bottom', 'Frequency', units='Hz')
        self.showGrid(x=True, y=True)

        left_axis=self.getAxis('left')
        left_axis.setGrid(255)

        # Invert y-axis so negative is "up" (corresponds with range)
        self.getViewBox().invertY(True)
        self.img.setCompositionMode(pg.QtGui.QPainter.CompositionMode_Plus)
        # self.setLabel('right', 'Range', 'm')
        # right_axis=self.getAxis('right')
        # right_axis.setScale((log_freq_range[-1] / self.img_array.shape[0]) * (FC / (2*spc.c)))
        if self.receiver.fft_mat is not None:
            downsampled = self.receiver.fft_mat[::self.downsample, ::self.downsample]
            print('rd - downsampled.shape', downsampled.shape)
            try:
                if not np.all(self.receiver.fast_fft_data == 0):
                    log_fft = 10 * np.log(downsampled)
                    print('log_fft.shape', log_fft.shape)
                    self.img.setImage(log_fft, autoLevels=False, autoDownsample=True)
            except:
                pass
            # print(self.getAxis("left").range)

    def update_fps(self):
        now = time.time()
        dt = now - self.lastTime
        self.lastTime = now
        if self.fps is None:
            self.fps = 1.0 / dt
        else:
            s = np.clip(dt * 3., 0, 1)
            self.fps = self.fps * (1 - s) + (1.0 / dt) * s
        print('%0.2f fps' % self.fps)

    def update(self):
        self.update_fps()

    def reset(self):
        # When paused, redraw after reset
        self.rescale()

    def rescale(self):
        self.img.resetTransform()

        self.update_period = \
            self.source.sample_chunk_size / self.source.sample_rate

        self.img.scale(self.receiver.slow_bin_size * self.downsample,
                       self.receiver.fast_bin_size * self.downsample)

        self.setRange(disableAutoRange=True, yRange=np.array(self.yrange))

        self.img.translate(-np.array(self.receiver.fft_mat.shape[1]) / (2 * self.downsample),
            -np.array(self.receiver.fft_mat.shape[0]) / (2 * self.downsample))

        self.setLimits(
            xMin=-self.source.sample_rate/(2*self.receiver.slow_bin_size), xMax=self.source.sample_rate/(2 * self.receiver.slow_bin_size))