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!["i", "i", "*+c", "i", "i", "2f", "d", "d", "f", "f", "i", "i"],
164        )?;
165
166        if get_data && result.len() >= 12 {
167            let channel_names = result[2].as_string_array()?.to_vec();
168            let data = result[5].as_f32_2d_array()?.to_vec();
169
170            Ok(Some(PLLFreqSwpData {
171                channel_names,
172                data,
173                characteristics: PLLFreqSwpCharacteristics {
174                    resonance_freq_hz: result[6].as_f64()?,
175                    q_factor: result[7].as_f64()?,
176                    phase_deg: result[8].as_f32()?,
177                    amp_exc_ratio_nm_per_mv: result[9].as_f32()?,
178                    fit_length: result[10].as_i32()?,
179                    num_points: result[11].as_i32()?,
180                },
181            }))
182        } else {
183            Ok(None)
184        }
185    }
186
187    /// Stop the PLL frequency sweep.
188    ///
189    /// # Arguments
190    /// * `modulator_index` - PLL modulator index (starts from 1)
191    ///
192    /// # Errors
193    /// Returns `NanonisError` if communication fails.
194    pub fn pll_freq_swp_stop(&mut self, modulator_index: i32) -> Result<(), NanonisError> {
195        self.quick_send(
196            "PLLFreqSwp.Stop",
197            vec![NanonisValue::I32(modulator_index)],
198            vec!["i"],
199            vec![],
200        )?;
201        Ok(())
202    }
203
204    // ==================== PLL Phase Sweep ====================
205
206    /// Start a PLL phase sweep.
207    ///
208    /// # Arguments
209    /// * `modulator_index` - PLL modulator index (starts from 1)
210    /// * `get_data` - If true, return recorded channels and data
211    ///
212    /// # Returns
213    /// Sweep data if `get_data` is true.
214    ///
215    /// # Errors
216    /// Returns `NanonisError` if communication fails.
217    pub fn pll_phas_swp_start(
218        &mut self,
219        modulator_index: i32,
220        get_data: bool,
221    ) -> Result<Option<PLLPhasSwpData>, NanonisError> {
222        let get_flag = if get_data { 1u32 } else { 0u32 };
223
224        let result = self.quick_send(
225            "PLLPhasSwp.Start",
226            vec![
227                NanonisValue::I32(modulator_index),
228                NanonisValue::U32(get_flag),
229            ],
230            vec!["i", "I"],
231            vec!["i", "i", "*+c", "i", "i", "2f"],
232        )?;
233
234        if get_data && result.len() >= 6 {
235            let channel_names = result[2].as_string_array()?.to_vec();
236            let data = result[5].as_f32_2d_array()?.to_vec();
237
238            Ok(Some(PLLPhasSwpData {
239                channel_names,
240                data,
241            }))
242        } else {
243            Ok(None)
244        }
245    }
246
247    /// Stop the PLL phase sweep.
248    ///
249    /// # Arguments
250    /// * `modulator_index` - PLL modulator index (starts from 1)
251    ///
252    /// # Errors
253    /// Returns `NanonisError` if communication fails.
254    pub fn pll_phas_swp_stop(&mut self, modulator_index: i32) -> Result<(), NanonisError> {
255        self.quick_send(
256            "PLLPhasSwp.Stop",
257            vec![NanonisValue::I32(modulator_index)],
258            vec!["i"],
259            vec![],
260        )?;
261        Ok(())
262    }
263}