Skip to main content

nanonis_rs/client/
spectrum_anlzr.rs

1use super::NanonisClient;
2use crate::error::NanonisError;
3use crate::types::NanonisValue;
4
5/// FFT window type for spectrum analyzer.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
7pub enum SpectrumFFTWindow {
8    #[default]
9    None = 0,
10    Hanning = 1,
11    Hamming = 2,
12    BlackmanHarris = 3,
13    ExactBlackman = 4,
14    Blackman = 5,
15    FlatTop = 6,
16    FourTermBHarris = 7,
17    SevenTermBHarris = 8,
18    LowSidelobe = 9,
19}
20
21impl From<SpectrumFFTWindow> for u16 {
22    fn from(window: SpectrumFFTWindow) -> Self {
23        window as u16
24    }
25}
26
27impl TryFrom<u16> for SpectrumFFTWindow {
28    type Error = NanonisError;
29
30    fn try_from(value: u16) -> Result<Self, Self::Error> {
31        match value {
32            0 => Ok(Self::None),
33            1 => Ok(Self::Hanning),
34            2 => Ok(Self::Hamming),
35            3 => Ok(Self::BlackmanHarris),
36            4 => Ok(Self::ExactBlackman),
37            5 => Ok(Self::Blackman),
38            6 => Ok(Self::FlatTop),
39            7 => Ok(Self::FourTermBHarris),
40            8 => Ok(Self::SevenTermBHarris),
41            9 => Ok(Self::LowSidelobe),
42            _ => Err(NanonisError::Protocol(format!(
43                "Invalid FFT window: {}",
44                value
45            ))),
46        }
47    }
48}
49
50/// Averaging mode for spectrum analyzer.
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
52pub enum SpectrumAveragingMode {
53    #[default]
54    None = 0,
55    Vector = 1,
56    RMS = 2,
57    PeakHold = 3,
58}
59
60impl From<SpectrumAveragingMode> for u16 {
61    fn from(mode: SpectrumAveragingMode) -> Self {
62        mode as u16
63    }
64}
65
66impl TryFrom<u16> for SpectrumAveragingMode {
67    type Error = NanonisError;
68
69    fn try_from(value: u16) -> Result<Self, Self::Error> {
70        match value {
71            0 => Ok(Self::None),
72            1 => Ok(Self::Vector),
73            2 => Ok(Self::RMS),
74            3 => Ok(Self::PeakHold),
75            _ => Err(NanonisError::Protocol(format!(
76                "Invalid averaging mode: {}",
77                value
78            ))),
79        }
80    }
81}
82
83/// Weighting mode for spectrum analyzer averaging.
84#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
85pub enum SpectrumWeightingMode {
86    #[default]
87    Linear = 0,
88    Exponential = 1,
89}
90
91impl From<SpectrumWeightingMode> for u16 {
92    fn from(mode: SpectrumWeightingMode) -> Self {
93        mode as u16
94    }
95}
96
97impl TryFrom<u16> for SpectrumWeightingMode {
98    type Error = NanonisError;
99
100    fn try_from(value: u16) -> Result<Self, Self::Error> {
101        match value {
102            0 => Ok(Self::Linear),
103            1 => Ok(Self::Exponential),
104            _ => Err(NanonisError::Protocol(format!(
105                "Invalid weighting mode: {}",
106                value
107            ))),
108        }
109    }
110}
111
112/// Cursor type for spectrum analyzer.
113#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
114pub enum SpectrumCursorType {
115    #[default]
116    XY = 0,
117    DxDy = 1,
118    X1X2Dx = 2,
119    Y1Y2Dy = 3,
120    RMSDf = 4,
121    NoChange = 5,
122}
123
124impl From<SpectrumCursorType> for u16 {
125    fn from(cursor: SpectrumCursorType) -> Self {
126        cursor as u16
127    }
128}
129
130impl TryFrom<u16> for SpectrumCursorType {
131    type Error = NanonisError;
132
133    fn try_from(value: u16) -> Result<Self, Self::Error> {
134        match value {
135            0 => Ok(Self::XY),
136            1 => Ok(Self::DxDy),
137            2 => Ok(Self::X1X2Dx),
138            3 => Ok(Self::Y1Y2Dy),
139            4 => Ok(Self::RMSDf),
140            5 => Ok(Self::NoChange),
141            _ => Err(NanonisError::Protocol(format!(
142                "Invalid cursor type: {}",
143                value
144            ))),
145        }
146    }
147}
148
149/// Spectrum analyzer instance (1 or 2).
150#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
151pub enum SpectrumAnalyzerInstance {
152    #[default]
153    Analyzer1 = 1,
154    Analyzer2 = 2,
155}
156
157impl From<SpectrumAnalyzerInstance> for i32 {
158    fn from(instance: SpectrumAnalyzerInstance) -> Self {
159        instance as i32
160    }
161}
162
163/// Frequency range information from spectrum analyzer.
164#[derive(Debug, Clone, Default)]
165pub struct SpectrumFreqRange {
166    /// Currently selected range index
167    pub selected_index: i32,
168    /// Available frequency ranges in Hz
169    pub available_ranges_hz: Vec<f32>,
170}
171
172/// Frequency resolution information from spectrum analyzer.
173#[derive(Debug, Clone, Default)]
174pub struct SpectrumFreqResolution {
175    /// Currently selected resolution index
176    pub selected_index: u16,
177    /// Available frequency resolutions in Hz
178    pub available_resolutions_hz: Vec<f32>,
179}
180
181/// Averaging configuration for spectrum analyzer.
182#[derive(Debug, Clone, Copy, Default)]
183pub struct SpectrumAveraging {
184    /// Averaging mode
185    pub mode: SpectrumAveragingMode,
186    /// Weighting mode
187    pub weighting: SpectrumWeightingMode,
188    /// Number of averages
189    pub count: u32,
190}
191
192/// Cursor position in spectrum analyzer.
193#[derive(Debug, Clone, Copy, Default)]
194pub struct SpectrumCursorPos {
195    /// X position of cursor 1 in Hz
196    pub cursor1_x_hz: f64,
197    /// X position of cursor 2 in Hz
198    pub cursor2_x_hz: f64,
199    /// Y position of cursor 1
200    pub cursor1_y: f64,
201}
202
203/// Band RMS measurement result.
204#[derive(Debug, Clone, Copy, Default)]
205pub struct SpectrumBandRMS {
206    /// RMS value in the frequency band
207    pub rms: f64,
208    /// Minimum frequency of the band in Hz
209    pub min_freq_hz: f64,
210    /// Maximum frequency of the band in Hz
211    pub max_freq_hz: f64,
212}
213
214/// Spectrum analyzer data.
215#[derive(Debug, Clone, Default)]
216pub struct SpectrumData {
217    /// X coordinate of the first acquired point (Hz)
218    pub f0_hz: f32,
219    /// Frequency distance between two acquired points (Hz)
220    pub df_hz: f32,
221    /// Acquired spectrum data
222    pub data: Vec<f32>,
223}
224
225impl NanonisClient {
226    // ==================== Spectrum Analyzer ====================
227
228    /// Set the channel to display in the spectrum analyzer.
229    ///
230    /// # Arguments
231    /// * `instance` - Spectrum analyzer instance (1 or 2)
232    /// * `channel_index` - Channel index (0-23) corresponding to signal slots
233    ///
234    /// # Errors
235    /// Returns `NanonisError` if communication fails.
236    pub fn spectrum_anlzr_ch_set(
237        &mut self,
238        instance: SpectrumAnalyzerInstance,
239        channel_index: i32,
240    ) -> Result<(), NanonisError> {
241        self.quick_send(
242            "SpectrumAnlzr.ChSet",
243            vec![
244                NanonisValue::I32(instance.into()),
245                NanonisValue::I32(channel_index),
246            ],
247            vec!["i", "i"],
248            vec![],
249        )?;
250        Ok(())
251    }
252
253    /// Get the channel displayed in the spectrum analyzer.
254    ///
255    /// # Arguments
256    /// * `instance` - Spectrum analyzer instance (1 or 2)
257    ///
258    /// # Returns
259    /// Channel index (0-23) corresponding to signal slots.
260    ///
261    /// # Errors
262    /// Returns `NanonisError` if communication fails.
263    pub fn spectrum_anlzr_ch_get(
264        &mut self,
265        instance: SpectrumAnalyzerInstance,
266    ) -> Result<i32, NanonisError> {
267        let result = self.quick_send(
268            "SpectrumAnlzr.ChGet",
269            vec![NanonisValue::I32(instance.into())],
270            vec!["i"],
271            vec!["i"],
272        )?;
273
274        result[0].as_i32()
275    }
276
277    /// Set the frequency range in the spectrum analyzer.
278    ///
279    /// Use `spectrum_anlzr_freq_range_get` first to get available ranges.
280    ///
281    /// # Arguments
282    /// * `instance` - Spectrum analyzer instance (1 or 2)
283    /// * `range_index` - Index of the desired frequency range
284    ///
285    /// # Errors
286    /// Returns `NanonisError` if communication fails.
287    pub fn spectrum_anlzr_freq_range_set(
288        &mut self,
289        instance: SpectrumAnalyzerInstance,
290        range_index: i32,
291    ) -> Result<(), NanonisError> {
292        self.quick_send(
293            "SpectrumAnlzr.FreqRangeSet",
294            vec![
295                NanonisValue::I32(instance.into()),
296                NanonisValue::I32(range_index),
297            ],
298            vec!["i", "i"],
299            vec![],
300        )?;
301        Ok(())
302    }
303
304    /// Get the frequency range configuration from the spectrum analyzer.
305    ///
306    /// # Arguments
307    /// * `instance` - Spectrum analyzer instance (1 or 2)
308    ///
309    /// # Returns
310    /// Frequency range information including selected index and available ranges.
311    ///
312    /// # Errors
313    /// Returns `NanonisError` if communication fails.
314    pub fn spectrum_anlzr_freq_range_get(
315        &mut self,
316        instance: SpectrumAnalyzerInstance,
317    ) -> Result<SpectrumFreqRange, NanonisError> {
318        let result = self.quick_send(
319            "SpectrumAnlzr.FreqRangeGet",
320            vec![NanonisValue::I32(instance.into())],
321            vec!["i"],
322            vec!["i", "i", "*f"],
323        )?;
324
325        Ok(SpectrumFreqRange {
326            selected_index: result[0].as_i32()?,
327            available_ranges_hz: result[2].as_f32_array()?.to_vec(),
328        })
329    }
330
331    /// Set the frequency resolution in the spectrum analyzer.
332    ///
333    /// Use `spectrum_anlzr_freq_res_get` first to get available resolutions.
334    ///
335    /// # Arguments
336    /// * `instance` - Spectrum analyzer instance (1 or 2)
337    /// * `resolution_index` - Index of the desired frequency resolution
338    ///
339    /// # Errors
340    /// Returns `NanonisError` if communication fails.
341    pub fn spectrum_anlzr_freq_res_set(
342        &mut self,
343        instance: SpectrumAnalyzerInstance,
344        resolution_index: u16,
345    ) -> Result<(), NanonisError> {
346        self.quick_send(
347            "SpectrumAnlzr.FreqResSet",
348            vec![
349                NanonisValue::I32(instance.into()),
350                NanonisValue::U16(resolution_index),
351            ],
352            vec!["i", "H"],
353            vec![],
354        )?;
355        Ok(())
356    }
357
358    /// Get the frequency resolution configuration from the spectrum analyzer.
359    ///
360    /// # Arguments
361    /// * `instance` - Spectrum analyzer instance (1 or 2)
362    ///
363    /// # Returns
364    /// Frequency resolution information including selected index and available resolutions.
365    ///
366    /// # Errors
367    /// Returns `NanonisError` if communication fails.
368    pub fn spectrum_anlzr_freq_res_get(
369        &mut self,
370        instance: SpectrumAnalyzerInstance,
371    ) -> Result<SpectrumFreqResolution, NanonisError> {
372        let result = self.quick_send(
373            "SpectrumAnlzr.FreqResGet",
374            vec![NanonisValue::I32(instance.into())],
375            vec!["i"],
376            vec!["H", "i", "*f"],
377        )?;
378
379        Ok(SpectrumFreqResolution {
380            selected_index: result[0].as_u16()?,
381            available_resolutions_hz: result[2].as_f32_array()?.to_vec(),
382        })
383    }
384
385    /// Set the FFT window in the spectrum analyzer.
386    ///
387    /// # Arguments
388    /// * `instance` - Spectrum analyzer instance (1 or 2)
389    /// * `window` - FFT window type
390    ///
391    /// # Errors
392    /// Returns `NanonisError` if communication fails.
393    pub fn spectrum_anlzr_fft_window_set(
394        &mut self,
395        instance: SpectrumAnalyzerInstance,
396        window: SpectrumFFTWindow,
397    ) -> Result<(), NanonisError> {
398        self.quick_send(
399            "SpectrumAnlzr.FFTWindowSet",
400            vec![
401                NanonisValue::I32(instance.into()),
402                NanonisValue::U16(window.into()),
403            ],
404            vec!["i", "H"],
405            vec![],
406        )?;
407        Ok(())
408    }
409
410    /// Get the FFT window from the spectrum analyzer.
411    ///
412    /// # Arguments
413    /// * `instance` - Spectrum analyzer instance (1 or 2)
414    ///
415    /// # Returns
416    /// Currently selected FFT window type.
417    ///
418    /// # Errors
419    /// Returns `NanonisError` if communication fails.
420    pub fn spectrum_anlzr_fft_window_get(
421        &mut self,
422        instance: SpectrumAnalyzerInstance,
423    ) -> Result<SpectrumFFTWindow, NanonisError> {
424        let result = self.quick_send(
425            "SpectrumAnlzr.FFTWindowGet",
426            vec![NanonisValue::I32(instance.into())],
427            vec!["i"],
428            vec!["H"],
429        )?;
430
431        SpectrumFFTWindow::try_from(result[0].as_u16()?)
432    }
433
434    /// Set the averaging parameters in the spectrum analyzer.
435    ///
436    /// # Arguments
437    /// * `instance` - Spectrum analyzer instance (1 or 2)
438    /// * `averaging` - Averaging configuration
439    ///
440    /// # Errors
441    /// Returns `NanonisError` if communication fails.
442    pub fn spectrum_anlzr_averag_set(
443        &mut self,
444        instance: SpectrumAnalyzerInstance,
445        averaging: &SpectrumAveraging,
446    ) -> Result<(), NanonisError> {
447        self.quick_send(
448            "SpectrumAnlzr.AveragSet",
449            vec![
450                NanonisValue::I32(instance.into()),
451                NanonisValue::U16(averaging.mode.into()),
452                NanonisValue::U16(averaging.weighting.into()),
453                NanonisValue::U32(averaging.count),
454            ],
455            vec!["i", "H", "H", "I"],
456            vec![],
457        )?;
458        Ok(())
459    }
460
461    /// Get the averaging parameters from the spectrum analyzer.
462    ///
463    /// # Arguments
464    /// * `instance` - Spectrum analyzer instance (1 or 2)
465    ///
466    /// # Returns
467    /// Averaging configuration.
468    ///
469    /// # Errors
470    /// Returns `NanonisError` if communication fails.
471    pub fn spectrum_anlzr_averag_get(
472        &mut self,
473        instance: SpectrumAnalyzerInstance,
474    ) -> Result<SpectrumAveraging, NanonisError> {
475        let result = self.quick_send(
476            "SpectrumAnlzr.AveragGet",
477            vec![NanonisValue::I32(instance.into())],
478            vec!["i"],
479            vec!["H", "H", "I"],
480        )?;
481
482        Ok(SpectrumAveraging {
483            mode: SpectrumAveragingMode::try_from(result[0].as_u16()?)?,
484            weighting: SpectrumWeightingMode::try_from(result[1].as_u16()?)?,
485            count: result[2].as_u32()?,
486        })
487    }
488
489    /// Set the AC coupling mode in the spectrum analyzer.
490    ///
491    /// Use `spectrum_anlzr_dc_get` to get the DC component when AC coupling is enabled.
492    ///
493    /// # Arguments
494    /// * `instance` - Spectrum analyzer instance (1 or 2)
495    /// * `enabled` - True to enable AC coupling, false to disable
496    ///
497    /// # Errors
498    /// Returns `NanonisError` if communication fails.
499    pub fn spectrum_anlzr_ac_coupling_set(
500        &mut self,
501        instance: SpectrumAnalyzerInstance,
502        enabled: bool,
503    ) -> Result<(), NanonisError> {
504        self.quick_send(
505            "SpectrumAnlzr.ACCouplingSet",
506            vec![
507                NanonisValue::I32(instance.into()),
508                NanonisValue::U32(if enabled { 1 } else { 0 }),
509            ],
510            vec!["i", "I"],
511            vec![],
512        )?;
513        Ok(())
514    }
515
516    /// Get the AC coupling mode from the spectrum analyzer.
517    ///
518    /// # Arguments
519    /// * `instance` - Spectrum analyzer instance (1 or 2)
520    ///
521    /// # Returns
522    /// True if AC coupling is enabled.
523    ///
524    /// # Errors
525    /// Returns `NanonisError` if communication fails.
526    pub fn spectrum_anlzr_ac_coupling_get(
527        &mut self,
528        instance: SpectrumAnalyzerInstance,
529    ) -> Result<bool, NanonisError> {
530        let result = self.quick_send(
531            "SpectrumAnlzr.ACCouplingGet",
532            vec![NanonisValue::I32(instance.into())],
533            vec!["i"],
534            vec!["I"],
535        )?;
536
537        Ok(result[0].as_u32()? != 0)
538    }
539
540    /// Set the cursor positions in the spectrum analyzer.
541    ///
542    /// Cursors 1 and 2 are used to define the frequency band.
543    ///
544    /// # Arguments
545    /// * `instance` - Spectrum analyzer instance (1 or 2)
546    /// * `cursor_type` - Type of cursor to display
547    /// * `cursor1_x_hz` - X position of cursor 1 in Hz
548    /// * `cursor2_x_hz` - X position of cursor 2 in Hz
549    ///
550    /// # Errors
551    /// Returns `NanonisError` if communication fails.
552    pub fn spectrum_anlzr_cursor_pos_set(
553        &mut self,
554        instance: SpectrumAnalyzerInstance,
555        cursor_type: SpectrumCursorType,
556        cursor1_x_hz: f64,
557        cursor2_x_hz: f64,
558    ) -> Result<(), NanonisError> {
559        self.quick_send(
560            "SpectrumAnlzr.CursorPosSet",
561            vec![
562                NanonisValue::I32(instance.into()),
563                NanonisValue::U16(cursor_type.into()),
564                NanonisValue::F64(cursor1_x_hz),
565                NanonisValue::F64(cursor2_x_hz),
566            ],
567            vec!["i", "H", "d", "d"],
568            vec![],
569        )?;
570        Ok(())
571    }
572
573    /// Get the cursor positions from the spectrum analyzer.
574    ///
575    /// # Arguments
576    /// * `instance` - Spectrum analyzer instance (1 or 2)
577    /// * `cursor_type` - Type of cursor to display (also sets the cursor type)
578    ///
579    /// # Returns
580    /// Cursor position information.
581    ///
582    /// # Errors
583    /// Returns `NanonisError` if communication fails.
584    pub fn spectrum_anlzr_cursor_pos_get(
585        &mut self,
586        instance: SpectrumAnalyzerInstance,
587        cursor_type: SpectrumCursorType,
588    ) -> Result<SpectrumCursorPos, NanonisError> {
589        let result = self.quick_send(
590            "SpectrumAnlzr.CursorPosGet",
591            vec![
592                NanonisValue::I32(instance.into()),
593                NanonisValue::U16(cursor_type.into()),
594            ],
595            vec!["i", "H"],
596            vec!["d", "d", "d"],
597        )?;
598
599        Ok(SpectrumCursorPos {
600            cursor1_x_hz: result[0].as_f64()?,
601            cursor2_x_hz: result[1].as_f64()?,
602            cursor1_y: result[2].as_f64()?,
603        })
604    }
605
606    /// Get the RMS value in the frequency band from the spectrum analyzer.
607    ///
608    /// This function sets the cursor type to Band RMS if previously set to another type.
609    ///
610    /// # Arguments
611    /// * `instance` - Spectrum analyzer instance (1 or 2)
612    ///
613    /// # Returns
614    /// Band RMS measurement including RMS value and frequency limits.
615    ///
616    /// # Errors
617    /// Returns `NanonisError` if communication fails.
618    pub fn spectrum_anlzr_band_rms_get(
619        &mut self,
620        instance: SpectrumAnalyzerInstance,
621    ) -> Result<SpectrumBandRMS, NanonisError> {
622        let result = self.quick_send(
623            "SpectrumAnlzr.BandRMSGet",
624            vec![NanonisValue::I32(instance.into())],
625            vec!["i"],
626            vec!["d", "d", "d"],
627        )?;
628
629        Ok(SpectrumBandRMS {
630            rms: result[0].as_f64()?,
631            min_freq_hz: result[1].as_f64()?,
632            max_freq_hz: result[2].as_f64()?,
633        })
634    }
635
636    /// Get the DC value from the spectrum analyzer.
637    ///
638    /// Only returns meaningful values when AC coupling mode is enabled.
639    ///
640    /// # Arguments
641    /// * `instance` - Spectrum analyzer instance (1 or 2)
642    ///
643    /// # Returns
644    /// DC value.
645    ///
646    /// # Errors
647    /// Returns `NanonisError` if communication fails.
648    pub fn spectrum_anlzr_dc_get(
649        &mut self,
650        instance: SpectrumAnalyzerInstance,
651    ) -> Result<f64, NanonisError> {
652        let result = self.quick_send(
653            "SpectrumAnlzr.DCGet",
654            vec![NanonisValue::I32(instance.into())],
655            vec!["i"],
656            vec!["d"],
657        )?;
658
659        result[0].as_f64()
660    }
661
662    /// Start the spectrum analyzer.
663    ///
664    /// The spectrum analyzer does not run when its front panel is closed.
665    /// Use this function to start the module for automated measurements.
666    ///
667    /// # Arguments
668    /// * `instance` - Spectrum analyzer instance (1 or 2)
669    ///
670    /// # Errors
671    /// Returns `NanonisError` if communication fails.
672    pub fn spectrum_anlzr_run(
673        &mut self,
674        instance: SpectrumAnalyzerInstance,
675    ) -> Result<(), NanonisError> {
676        self.quick_send(
677            "SpectrumAnlzr.Run",
678            vec![NanonisValue::I32(instance.into())],
679            vec!["i"],
680            vec![],
681        )?;
682        Ok(())
683    }
684
685    /// Get the data from the spectrum analyzer.
686    ///
687    /// # Arguments
688    /// * `instance` - Spectrum analyzer instance (1 or 2)
689    ///
690    /// # Returns
691    /// Spectrum data including frequency axis and amplitude values.
692    ///
693    /// # Errors
694    /// Returns `NanonisError` if communication fails.
695    pub fn spectrum_anlzr_data_get(
696        &mut self,
697        instance: SpectrumAnalyzerInstance,
698    ) -> Result<SpectrumData, NanonisError> {
699        let result = self.quick_send(
700            "SpectrumAnlzr.DataGet",
701            vec![NanonisValue::I32(instance.into())],
702            vec!["i"],
703            vec!["f", "f", "i", "*f"],
704        )?;
705
706        Ok(SpectrumData {
707            f0_hz: result[0].as_f32()?,
708            df_hz: result[1].as_f32()?,
709            data: result[3].as_f32_array()?.to_vec(),
710        })
711    }
712}