📄 gr_oscope_guts.cc
字号:
/* -*- c++ -*- *//* * Copyright 2003 Free Software Foundation, Inc. * * This file is part of GNU Radio * * GNU Radio 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, or (at your option) * any later version. * * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#include <gr_oscope_guts.h>#include <stdexcept>#include <stdio.h>#include <algorithm>#include <unistd.h>#include <math.h>#include <assert.h>static const int OUTPUT_RECORD_SIZE = 2048; // must be power of 2static inline intwrap_bi (int buffer_index) // wrap buffer index{ return buffer_index & (OUTPUT_RECORD_SIZE - 1);}static inline intincr_bi (int buffer_index) // increment buffer index{ return wrap_bi (buffer_index + 1);}static inline intdecr_bi (int buffer_index) // decrement buffer index{ return wrap_bi (buffer_index - 1);}gr_oscope_guts::gr_oscope_guts (int nchannels, double sample_rate, int output_fd) : d_nchannels (nchannels), d_output_fd (output_fd), d_trigger_mode (gr_TRIG_POS_SLOPE), d_trigger_channel (0), d_sample_rate (sample_rate), d_update_rate (20), d_trigger_level (0), d_obi (0), d_state (LOOK_FOR_TRIGGER), d_decimator_count (0), d_decimator_count_init (1), d_hold_off_count (0), d_hold_off_count_init (0), d_post_trigger_count (0), d_post_trigger_count_init (OUTPUT_RECORD_SIZE/2), d_prev_sample (0){ if (d_nchannels > MAX_CHANNELS){ fprintf (stderr, "gr_oscope_guts: too many channels. MAX_CHANNELS = %d\n", MAX_CHANNELS); throw std::runtime_error ("too many channels"); } for (int i = 0; i < MAX_CHANNELS; i++) d_buffer[i] = 0; for (int i = 0; i < d_nchannels; i++) d_buffer[i] = new float [OUTPUT_RECORD_SIZE]; update_rate_or_decimation_changed (); enter_look_for_trigger ();}gr_oscope_guts::~gr_oscope_guts (){ for (int i = 0; i < MAX_CHANNELS; i++) delete [] d_buffer[i];}// MANIPULATORS// \p channel_data points to nchannels float values. These are the values// for each channel at this sample time.voidgr_oscope_guts::process_sample (const float *channel_data){ d_decimator_count--; if (d_decimator_count > 0) return; d_decimator_count = d_decimator_count_init; for (int i = 0; i < d_nchannels; i++) d_buffer[i][d_obi] = channel_data[i]; // copy data into buffer int trigger = 0; switch (d_state){ case HOLD_OFF: d_hold_off_count--; if (d_hold_off_count <= 0) enter_look_for_trigger (); break; case LOOK_FOR_TRIGGER: trigger = found_trigger (d_buffer[d_trigger_channel][d_obi]); if (trigger != 0){ enter_post_trigger (); if (trigger < 0) // previous sample was closer d_post_trigger_count--; } break; case POST_TRIGGER: d_post_trigger_count--; if (d_post_trigger_count <= 0){ write_output_records (); enter_hold_off (); } break; default: assert (0); } d_obi = incr_bi (d_obi);}/* * Functions called on state entry */voidgr_oscope_guts::enter_hold_off (){ d_state = HOLD_OFF; d_hold_off_count = d_hold_off_count_init;}voidgr_oscope_guts::enter_look_for_trigger (){ d_state = LOOK_FOR_TRIGGER; d_prev_sample = d_buffer[d_trigger_channel][d_obi];}voidgr_oscope_guts::enter_post_trigger (){ d_state = POST_TRIGGER; d_post_trigger_count = d_post_trigger_count_init;}// ----------------------------------------------------------------// returns 0 if no trigger found. // returns +1 if this sample is the trigger point// returns -1 if the previous sample is the trigger pointintgr_oscope_guts::found_trigger (float new_sample){ float prev_sample = d_prev_sample; d_prev_sample = new_sample; bool trig; switch (d_trigger_mode){ case gr_TRIG_AUTO: // always trigger return +1; case gr_TRIG_POS_SLOPE: trig = prev_sample < d_trigger_level && new_sample > d_trigger_level; if (trig){ if (fabs (prev_sample - d_trigger_level) < fabs (new_sample - d_trigger_level)) return -1; else return +1; } return 0; case gr_TRIG_NEG_SLOPE: trig = prev_sample > d_trigger_level && new_sample < d_trigger_level; if (trig){ if (fabs (prev_sample - d_trigger_level) < fabs (new_sample - d_trigger_level)) return -1; else return +1; } return 0; default: assert (0); return 0; }}// ----------------------------------------------------------------// write output records (duh!)voidgr_oscope_guts::write_output_records (){ float tmp[OUTPUT_RECORD_SIZE]; int header[2]; header[0] = d_nchannels; header[1] = OUTPUT_RECORD_SIZE; write (d_output_fd, header, sizeof (header)); for (int ch = 0; ch < d_nchannels; ch++){ // be lazy, make them linear, then write them // note that d_obi points at the oldest sample in the buffer for (int i = 0; i < OUTPUT_RECORD_SIZE; i++) tmp[i] = d_buffer[ch][wrap_bi(d_obi + i)]; if (write (d_output_fd, tmp, sizeof (tmp)) != sizeof (tmp)) perror ("gr_oscope_guts/write"); }}// ----------------------------------------------------------------boolgr_oscope_guts::set_update_rate (double update_rate){ d_update_rate = std::min (std::max (1./10., update_rate), d_sample_rate); update_rate_or_decimation_changed (); return true;}boolgr_oscope_guts::set_decimation_count (int decimator_count){ decimator_count = std::max (1, decimator_count); d_decimator_count_init = decimator_count; update_rate_or_decimation_changed (); return true;}voidgr_oscope_guts::update_rate_or_decimation_changed (){ d_hold_off_count_init = (int) rint (d_sample_rate / d_update_rate / d_decimator_count_init);}boolgr_oscope_guts::set_trigger_channel (int channel){ if (channel >= 0 && channel < d_nchannels){ d_trigger_channel = channel; trigger_changed (); return true; } return false;}boolgr_oscope_guts::set_trigger_mode (gr_trigger_mode mode){ switch (mode){ case gr_TRIG_POS_SLOPE: case gr_TRIG_NEG_SLOPE: case gr_TRIG_AUTO: d_trigger_mode = mode; trigger_changed (); return true; } return false;}boolgr_oscope_guts::set_trigger_level (double trigger_level){ d_trigger_level = trigger_level; trigger_changed (); return true;}boolgr_oscope_guts::set_trigger_level_auto (){ // find the level 1/2 way between the min and the max float min_v = d_buffer[d_trigger_channel][0]; float max_v = d_buffer[d_trigger_channel][0]; for (int i = 1; i < OUTPUT_RECORD_SIZE; i++){ min_v = std::min (min_v, d_buffer[d_trigger_channel][i]); max_v = std::max (max_v, d_buffer[d_trigger_channel][i]); } d_trigger_level = (min_v + max_v) * 0.5; trigger_changed (); return true;}voidgr_oscope_guts::trigger_changed (){ // d_prev_sample = d_buffer[d_trigger_channel][decr_bi(d_obi)]; enter_look_for_trigger ();}// ACCESSORSintgr_oscope_guts::num_channels () const{ return d_nchannels;}doublegr_oscope_guts::sampling_rate () const{ return d_sample_rate;}doublegr_oscope_guts::update_rate () const{ return d_update_rate;}intgr_oscope_guts::get_decimation_count () const{ return d_decimator_count_init;}intgr_oscope_guts::get_trigger_channel () const{ return d_trigger_channel;}gr_trigger_modegr_oscope_guts::get_trigger_mode () const{ return d_trigger_mode;}doublegr_oscope_guts::get_trigger_level () const{ return d_trigger_level;}intgr_oscope_guts::get_samples_per_output_record () const{ return OUTPUT_RECORD_SIZE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -