From 0c68c486ec09da471c27b6f4d658ae0ba8f861b7 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 31 Aug 2009 18:18:22 -0700 Subject: Modified log power fft block so ref scale is peak to peak. Tweaked fft sink autoscale routine to come up with better numbers. Modified scope sink ac couple block to use constant tap. The previous tap calculation would cause failure for very small sample rates. --- gr-wxgui/src/python/fft_window.py | 20 ++++++++++++-------- gr-wxgui/src/python/scopesink_gl.py | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) (limited to 'gr-wxgui') diff --git a/gr-wxgui/src/python/fft_window.py b/gr-wxgui/src/python/fft_window.py index 0529e6a5d..4c575f1a6 100644 --- a/gr-wxgui/src/python/fft_window.py +++ b/gr-wxgui/src/python/fft_window.py @@ -256,15 +256,19 @@ class fft_window(wx.Panel, pubsub.pubsub): if not len(self.samples): return #get the peak level (max of the samples) peak_level = numpy.max(self.samples) - #get the noise floor (averge the smallest samples) - noise_floor = numpy.average(numpy.sort(self.samples)[:len(self.samples)/4]) - #padding - noise_floor -= abs(noise_floor)*.5 - peak_level += abs(peak_level)*.1 - #set the reference level to a multiple of y divs - self[REF_LEVEL_KEY] = self[Y_DIVS_KEY]*math.ceil(peak_level/self[Y_DIVS_KEY]) + #separate noise samples + noise_samps = numpy.sort(self.samples)[:len(self.samples)/2] + #get the noise floor + noise_floor = numpy.average(noise_samps) + #get the noise deviation + noise_dev = numpy.std(noise_samps) + #determine the maximum and minimum levels + max_level = peak_level + min_level = noise_floor - abs(2*noise_dev) #set the range to a clean number of the dynamic range - self[Y_PER_DIV_KEY] = common.get_clean_num((peak_level - noise_floor)/self[Y_DIVS_KEY]) + self[Y_PER_DIV_KEY] = common.get_clean_num(1+(max_level - min_level)/self[Y_DIVS_KEY]) + #set the reference level to a multiple of y per div + self[REF_LEVEL_KEY] = self[Y_PER_DIV_KEY]*round(.5+max_level/self[Y_PER_DIV_KEY]) def _reset_peak_vals(self, *args): self.peak_vals = EMPTY_TRACE diff --git a/gr-wxgui/src/python/scopesink_gl.py b/gr-wxgui/src/python/scopesink_gl.py index b4ae0f339..a5e3ca3ce 100644 --- a/gr-wxgui/src/python/scopesink_gl.py +++ b/gr-wxgui/src/python/scopesink_gl.py @@ -50,7 +50,7 @@ class ac_couple_block(gr.hier_block2): self.connect(self, lpf, mute, (sub, 1)) #subscribe controller.subscribe(ac_couple_key, lambda x: mute.set_mute(not x)) - controller.subscribe(sample_rate_key, lambda x: lpf.set_taps(2.0/x)) + controller.subscribe(sample_rate_key, lambda x: lpf.set_taps(0.05)) #initialize controller[ac_couple_key] = ac_couple controller[sample_rate_key] = controller[sample_rate_key] -- cgit From eb1d1b5cfb474b087d41337356efc0cdb7342f28 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 2 Sep 2009 14:06:34 -0700 Subject: Fix so that the waterfall texture is initialized with a buffer of the same size. If the fft size was a non power of two, the buffer would be a different size. This would cause a segfault. Particularly because fft_window was throwing out a bin. --- gr-wxgui/src/python/plotter/waterfall_plotter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-wxgui') diff --git a/gr-wxgui/src/python/plotter/waterfall_plotter.py b/gr-wxgui/src/python/plotter/waterfall_plotter.py index 2e0669961..d32b0ca0a 100644 --- a/gr-wxgui/src/python/plotter/waterfall_plotter.py +++ b/gr-wxgui/src/python/plotter/waterfall_plotter.py @@ -209,7 +209,7 @@ class waterfall_plotter(grid_plotter_base): self._pointer = 0 if self._num_lines and self._fft_size: GL.glBindTexture(GL.GL_TEXTURE_2D, self._waterfall_texture) - data = numpy.zeros(self._num_lines*self._fft_size*4, numpy.uint8).tostring() + data = numpy.zeros(self._num_lines*ceil_log2(self._fft_size)*4, numpy.uint8).tostring() GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, ceil_log2(self._fft_size), self._num_lines, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, data) self._resize_texture_flag = False -- cgit From a70c291e3cd4fc3d51f2eebb6b39cdb9d46862da Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 2 Sep 2009 14:18:28 -0700 Subject: waterfall and fft use a common autoscale function --- gr-wxgui/src/python/common.py | 25 ++++++++++++++++++++++--- gr-wxgui/src/python/fft_window.py | 12 +----------- gr-wxgui/src/python/waterfall_window.py | 12 +++--------- 3 files changed, 26 insertions(+), 23 deletions(-) (limited to 'gr-wxgui') diff --git a/gr-wxgui/src/python/common.py b/gr-wxgui/src/python/common.py index d555a1f05..9c97ce1ec 100644 --- a/gr-wxgui/src/python/common.py +++ b/gr-wxgui/src/python/common.py @@ -137,6 +137,25 @@ def get_min_max(samples): scale_factor = 3 mean = numpy.average(samples) rms = numpy.max([scale_factor*((numpy.sum((samples-mean)**2)/len(samples))**.5), .1]) - min = mean - rms - max = mean + rms - return min, max + min_val = mean - rms + max_val = mean + rms + return min_val, max_val + +def get_min_max_fft(fft_samps): + """ + Get the minimum and maximum bounds for an array of fft samples. + @param samples the array of real values + @return a tuple of min, max + """ + #get the peak level (max of the samples) + peak_level = numpy.max(fft_samps) + #separate noise samples + noise_samps = numpy.sort(fft_samps)[:len(fft_samps)/2] + #get the noise floor + noise_floor = numpy.average(noise_samps) + #get the noise deviation + noise_dev = numpy.std(noise_samps) + #determine the maximum and minimum levels + max_level = peak_level + min_level = noise_floor - abs(2*noise_dev) + return min_level, max_level diff --git a/gr-wxgui/src/python/fft_window.py b/gr-wxgui/src/python/fft_window.py index 4c575f1a6..237c8940c 100644 --- a/gr-wxgui/src/python/fft_window.py +++ b/gr-wxgui/src/python/fft_window.py @@ -254,17 +254,7 @@ class fft_window(wx.Panel, pubsub.pubsub): Set the dynamic range and reference level. """ if not len(self.samples): return - #get the peak level (max of the samples) - peak_level = numpy.max(self.samples) - #separate noise samples - noise_samps = numpy.sort(self.samples)[:len(self.samples)/2] - #get the noise floor - noise_floor = numpy.average(noise_samps) - #get the noise deviation - noise_dev = numpy.std(noise_samps) - #determine the maximum and minimum levels - max_level = peak_level - min_level = noise_floor - abs(2*noise_dev) + min_level, max_level = common.get_min_max_fft(self.samples) #set the range to a clean number of the dynamic range self[Y_PER_DIV_KEY] = common.get_clean_num(1+(max_level - min_level)/self[Y_DIVS_KEY]) #set the reference level to a multiple of y per div diff --git a/gr-wxgui/src/python/waterfall_window.py b/gr-wxgui/src/python/waterfall_window.py index c00992e14..28e67a830 100644 --- a/gr-wxgui/src/python/waterfall_window.py +++ b/gr-wxgui/src/python/waterfall_window.py @@ -237,16 +237,10 @@ class waterfall_window(wx.Panel, pubsub.pubsub): Does not affect the current data in the waterfall. """ if not len(self.samples): return - #get the peak level (max of the samples) - peak_level = numpy.max(self.samples) - #get the noise floor (averge the smallest samples) - noise_floor = numpy.average(numpy.sort(self.samples)[:len(self.samples)/4]) - #padding - noise_floor -= abs(noise_floor)*.5 - peak_level += abs(peak_level)*.1 + min_level, max_level = common.get_min_max_fft(self.samples) #set the range and level - self[REF_LEVEL_KEY] = peak_level - self[DYNAMIC_RANGE_KEY] = peak_level - noise_floor + self[REF_LEVEL_KEY] = max_level + self[DYNAMIC_RANGE_KEY] = max_level - min_level def handle_msg(self, msg): """ -- cgit