public void CalcSpectrum(int filter_low, int filter_high, int spec_blocksize, int sample_rate) { //filter_low is the low frequency setting for the filter //filter_high is the high frequency setting for the filter //samplerate is the current samplerate //fft_size is the current FFT size //no spur elimination => only one spur_elim_fft and it's spectrum is not flipped int[] flip = { 0 }; GCHandle handle = GCHandle.Alloc(flip, GCHandleType.Pinned); IntPtr h_flip = handle.AddrOfPinnedObject(); // const int extra = 1000; //if we allow a little extra spectrum to be displayed on each side of // the filter settings, then, you can look at filter rolloff. This // seems to happen at least some of the time with the old spectrum display. // "extra" is the amount extra to leave on each side of the filter bandwidth // and is in Hertz. //the upper and lower limits of the displayed spectrum would be int upper_freq = filter_high; // +extra; int lower_freq = filter_low; // -extra; //bandwidth to clip off on the high and low sides double high_clip_bw = 0.5 * sample_rate - upper_freq; double low_clip_bw = 0.5 * sample_rate + lower_freq; //calculate the width of each frequency bin double bin_width = (double)sample_rate / fft_size; //calculate span clip parameters int fsclipH = (int)Math.Floor(high_clip_bw / bin_width); int fsclipL = (int)Math.Ceiling(low_clip_bw / bin_width); //no need for any symmetrical clipping int sclip = 0; int stitch = 1; max_w = fft_size + (int)Math.Min(KEEP_TIME * sample_rate, KEEP_TIME * fft_size * frame_rate); Display.RXSpectrumDisplayLow = lower_freq; Display.RXSpectrumDisplayHigh = upper_freq; // set overlap as needed to achieve the desired frame rate overlap = (int)Math.Max(0.0, Math.Ceiling(fft_size - (double)sample_rate / (double)frame_rate)); SpecHPSDRDLL.SetAnalyzer( disp, 2, spur_eliminationtion_ffts, data_type, h_flip, fft_size, spec_blocksize, window_type, kaiser_pi, overlap, sclip, fsclipL, fsclipH, pixels, stitch, calibration_data_set, span_min_freq, span_max_freq, max_w); }
public void initAnalyzer() { //no spur elimination => only one spur_elim_fft and it's spectrum is not flipped int[] flip = { 0 }; GCHandle handle = GCHandle.Alloc(flip, GCHandleType.Pinned); IntPtr h_flip = handle.AddrOfPinnedObject(); int low = 0; int high = 0; int low_tx = 0; int high_tx = 0; double bw_per_subspan = 0.0; double bw_per_subspan_tx = 0.0; switch (data_type) { case 0: //real fft - in case we want to use for wideband data in the future { break; } case 1: //complex fft { //fraction of the spectrum to clip off each side of each sub-span const double CLIP_FRACTION = 0.017; //set overlap as needed to achieve the desired frame_rate overlap = (int)Math.Max(0.0, Math.Ceiling(fft_size - (double)sample_rate / (double)frame_rate)); //clip is the number of bins to clip off each side of each sub-span clip = (int)Math.Floor(CLIP_FRACTION * fft_size); //the amount of frequency in each fft bin (for complex samples) is given by: double bin_width = (double)sample_rate / (double)fft_size; double bin_width_tx = 96000.0 / (double)fft_size; //the number of useable bins per subspan is int bins_per_subspan = fft_size - 2 * clip; //the amount of useable bandwidth we get from each subspan is: bw_per_subspan = bins_per_subspan * bin_width; bw_per_subspan_tx = bins_per_subspan * bin_width_tx; //the total number of bins available to display is: int bins = stitches * bins_per_subspan; //apply log function to zoom slider value double zoom_slider = Math.Log10(9.0 * z_slider + 1.0); //limits how much you can zoom in; higher value means you zoom more const double zoom_limit = 100; int width = (int)(bins * (1.0 - (1.0 - 1.0 / zoom_limit) * zoom_slider)); //FSCLIPL is 0 if pan_slider is 0; it's bins-width if pan_slider is 1 //FSCLIPH is bins-width if pan_slider is 0; it's 0 if pan_slider is 1 span_clip_l = (int)Math.Floor(pan_slider * (bins - width)); span_clip_h = bins - width - span_clip_l; if (Display.RX1DSPMode == DSPMode.DRM) { //Apply any desired frequency offset int bin_offset = (int)(freq_offset / bin_width); if ((span_clip_h -= bin_offset) < 0) { span_clip_h = 0; } span_clip_l = bins - width - span_clip_h; } //As for the low and high frequencies that are being displayed: low = -(int)((double)stitches / 2.0 * bw_per_subspan - (double)span_clip_l * bin_width + bin_width / 2.0); high = +(int)((double)stitches / 2.0 * bw_per_subspan - (double)span_clip_h * bin_width - bin_width / 2.0); low_tx = -(int)((double)stitches / 2.0 * bw_per_subspan_tx - (double)span_clip_l * bin_width_tx + bin_width_tx / 2.0); high_tx = +(int)((double)stitches / 2.0 * bw_per_subspan_tx - (double)span_clip_h * bin_width_tx - bin_width_tx / 2.0); //Note that the bin_width/2.0 factors are included because the complex FFT has one more negative output bin // than positive output bin. max_w = fft_size + (int)Math.Min(KEEP_TIME * sample_rate, KEEP_TIME * fft_size * frame_rate); break; } } switch (disp) { case 0: Display.RXDisplayLow = low; Display.RXDisplayHigh = high; if (Display.CurrentDisplayMode == DisplayMode.WATERFALL || Display.CurrentDisplayMode == DisplayMode.PANAFALL) { Display.TXDisplayLow = low_tx; Display.TXDisplayHigh = high_tx; } break; case 1: Display.RX2DisplayLow = low; Display.RX2DisplayHigh = high; if (!(Display.CurrentDisplayMode == DisplayMode.WATERFALL || Display.CurrentDisplayMode == DisplayMode.PANAFALL)) { Display.TXDisplayLow = low_tx; Display.TXDisplayHigh = high_tx; } break; } JanusAudio.LowFreqOffset = bw_per_subspan; JanusAudio.HighFreqOffset = bw_per_subspan; if (disp == 0) { if (Display.CurrentDisplayMode != DisplayMode.PANADAPTER && Display.CurrentDisplayMode != DisplayMode.WATERFALL && Display.CurrentDisplayMode != DisplayMode.PANAFALL && Display.CurrentDisplayMode != DisplayMode.PANASCOPE) { return; } } SpecHPSDRDLL.SetAnalyzer( disp, 2, spur_eliminationtion_ffts, data_type, h_flip, fft_size, blocksize, window_type, kaiser_pi, overlap, clip, span_clip_l, span_clip_h, pixels, stitches, calibration_data_set, span_min_freq, span_max_freq, max_w); }