Skip to main content

nanonis_rs/client/
pll_freq_swp.rs

1use super::NanonisClient;
2use crate::error::NanonisError;
3use crate::types::NanonisValue;
4
5/// PLL frequency sweep parameters.
6#[derive(Debug, Clone, Copy, Default)]
7pub struct PLLFreqSwpParams {
8    /// Number of points in sweep
9    pub num_points: i32,
10    /// Measurement/wait period in seconds
11    pub period_s: f32,
12    /// Initial settling time in seconds
13    pub settling_time_s: f32,
14}
15
16/// PLL frequency sweep characteristic values.
17#[derive(Debug, Clone, Copy, Default)]
18pub struct PLLFreqSwpCharacteristics {
19    /// Resonance frequency in Hz
20    pub resonance_freq_hz: f64,
21    /// Quality factor
22    pub q_factor: f64,
23    /// Phase at resonance in degrees
24    pub phase_deg: f32,
25    /// Amplitude to excitation ratio in nm/mV
26    pub amp_exc_ratio_nm_per_mv: f32,
27    /// Fit length (samples)
28    pub fit_length: i32,
29    /// Number of points
30    pub num_points: i32,
31}
32
33/// PLL frequency sweep result data.
34#[derive(Debug, Clone, Default)]
35pub struct PLLFreqSwpData {
36    /// Channel names
37    pub channel_names: Vec<String>,
38    /// Data rows (one per point)
39    pub data: Vec<Vec<f32>>,
40    /// Sweep characteristics
41    pub characteristics: PLLFreqSwpCharacteristics,
42}
43
44/// PLL phase sweep result data.
45#[derive(Debug, Clone, Default)]
46pub struct PLLPhasSwpData {
47    /// Channel names
48    pub channel_names: Vec<String>,
49    /// Data rows (one per point)
50    pub data: Vec<Vec<f32>>,
51}
52
53impl NanonisClient {
54    // ==================== PLL Frequency Sweep ====================
55
56    /// Open the PLL frequency sweep module.
57    ///
58    /// # Arguments
59    /// * `modulator_index` - PLL modulator index (starts from 1)
60    ///
61    /// # Errors
62    /// Returns `NanonisError` if communication fails.
63    pub fn pll_freq_swp_open(&mut self, modulator_index: i32) -> Result<(), NanonisError> {
64        self.quick_send(
65            "PLLFreqSwp.Open",
66            vec![NanonisValue::I32(modulator_index)],
67            vec!["i"],
68            vec![],
69        )?;
70        Ok(())
71    }
72
73    /// Set the PLL frequency sweep parameters.
74    ///
75    /// # Arguments
76    /// * `modulator_index` - PLL modulator index (starts from 1)
77    /// * `params` - Sweep parameters
78    ///
79    /// # Errors
80    /// Returns `NanonisError` if communication fails.
81    pub fn pll_freq_swp_params_set(
82        &mut self,
83        modulator_index: i32,
84        params: &PLLFreqSwpParams,
85    ) -> Result<(), NanonisError> {
86        self.quick_send(
87            "PLLFreqSwp.ParamsSet",
88            vec![
89                NanonisValue::I32(modulator_index),
90                NanonisValue::I32(params.num_points),
91                NanonisValue::F32(params.period_s),
92                NanonisValue::F32(params.settling_time_s),
93            ],
94            vec!["i", "i", "f", "f"],
95            vec![],
96        )?;
97        Ok(())
98    }
99
100    /// Get the PLL frequency sweep parameters.
101    ///
102    /// # Arguments
103    /// * `modulator_index` - PLL modulator index (starts from 1)
104    ///
105    /// # Returns
106    /// Sweep parameters.
107    ///
108    /// # Errors
109    /// Returns `NanonisError` if communication fails.
110    pub fn pll_freq_swp_params_get(
111        &mut self,
112        modulator_index: i32,
113    ) -> Result<PLLFreqSwpParams, NanonisError> {
114        let result = self.quick_send(
115            "PLLFreqSwp.ParamsGet",
116            vec![NanonisValue::I32(modulator_index)],
117            vec!["i"],
118            vec!["i", "f", "f"],
119        )?;
120
121        if result.len() >= 3 {
122            Ok(PLLFreqSwpParams {
123                num_points: result[0].as_i32()?,
124                period_s: result[1].as_f32()?,
125                settling_time_s: result[2].as_f32()?,
126            })
127        } else {
128            Err(NanonisError::Protocol("Invalid response".to_string()))
129        }
130    }
131
132    /// Start a PLL frequency sweep.
133    ///
134    /// Set center frequency and frequency range in Oscillation Control module first.
135    ///
136    /// # Arguments
137    /// * `modulator_index` - PLL modulator index (starts from 1)
138    /// * `get_data` - If true, return recorded channels and data
139    /// * `sweep_up` - If true, sweep from lower to upper limit
140    ///
141    /// # Returns
142    /// Sweep data and characteristics if `get_data` is true.
143    ///
144    /// # Errors
145    /// Returns `NanonisError` if communication fails.
146    pub fn pll_freq_swp_start(
147        &mut self,
148        modulator_index: i32,
149        get_data: bool,
150        sweep_up: bool,
151    ) -> Result<Option<PLLFreqSwpData>, NanonisError> {
152        let get_flag = if get_data { 1u32 } else { 0u32 };
153        let dir_flag = if sweep_up { 1u32 } else { 0u32 };
154
155        let result = self.quick_send(
156            "PLLFreqSwp.Start",
157            vec![
158                NanonisValue::I32(modulator_index),
159                NanonisValue::U32(get_flag),
160                NanonisValue::U32(dir_flag),
161            ],
162            vec!["i", "I", "I"],
163            vec![
164                "i", "i", "*+c", "i", "i", "2f", "d", "d", "f", "f", "i", "i",
165            ],
166        )?;
167
168        if get_data && result.len() >= 12 {
169            let channel_names = result[2].as_string_array()?.to_vec();
170            let data = result[5].as_f32_2d_array()?.to_vec();
171
172            Ok(Some(PLLFreqSwpData {
173                channel_names,
174                data,
175                characteristics: PLLFreqSwpCharacteristics {
176                    resonance_freq_hz: result[6].as_f64()?,
177                    q_factor: result[7].as_f64()?,
178                    phase_deg: result[8].as_f32()?,
179                    amp_exc_ratio_nm_per_mv: result[9].as_f32()?,
180                    fit_length: result[10].as_i32()?,
181                    num_points: result[11].as_i32()?,
182                },
183            }))
184        } else {
185            Ok(None)
186        }
187    }
188
189    /// Stop the PLL frequency sweep.
190    ///
191    /// # Arguments
192    /// * `modulator_index` - PLL modulator index (starts from 1)
193    ///
194    /// # Errors
195    /// Returns `NanonisError` if communication fails.
196    pub fn pll_freq_swp_stop(&mut self, modulator_index: i32) -> Result<(), NanonisError> {
197        self.quick_send(
198            "PLLFreqSwp.Stop",
199            vec![NanonisValue::I32(modulator_index)],
200            vec!["i"],
201            vec![],
202        )?;
203        Ok(())
204    }
205
206    // ==================== PLL Phase Sweep ====================
207
208    /// Start a PLL phase sweep.
209    ///
210    /// # Arguments
211    /// * `modulator_index` - PLL modulator index (starts from 1)
212    /// * `get_data` - If true, return recorded channels and data
213    ///
214    /// # Returns
215    /// Sweep data if `get_data` is true.
216    ///
217    /// # Errors
218    /// Returns `NanonisError` if communication fails.
219    pub fn pll_phas_swp_start(
220        &mut self,
221        modulator_index: i32,
222        get_data: bool,
223    ) -> Result<Option<PLLPhasSwpData>, NanonisError> {
224        let get_flag = if get_data { 1u32 } else { 0u32 };
225
226        let result = self.quick_send(
227            "PLLPhasSwp.Start",
228            vec![
229                NanonisValue::I32(modulator_index),
230                NanonisValue::U32(get_flag),
231            ],
232            vec!["i", "I"],
233            vec!["i", "i", "*+c", "i", "i", "2f"],
234        )?;
235
236        if get_data && result.len() >= 6 {
237            let channel_names = result[2].as_string_array()?.to_vec();
238            let data = result[5].as_f32_2d_array()?.to_vec();
239
240            Ok(Some(PLLPhasSwpData {
241                channel_names,
242                data,
243            }))
244        } else {
245            Ok(None)
246        }
247    }
248
249    /// Stop the PLL phase sweep.
250    ///
251    /// # Arguments
252    /// * `modulator_index` - PLL modulator index (starts from 1)
253    ///
254    /// # Errors
255    /// Returns `NanonisError` if communication fails.
256    pub fn pll_phas_swp_stop(&mut self, modulator_index: i32) -> Result<(), NanonisError> {
257        self.quick_send(
258            "PLLPhasSwp.Stop",
259            vec![NanonisValue::I32(modulator_index)],
260            vec!["i"],
261            vec![],
262        )?;
263        Ok(())
264    }
265}