44#
55# SPDX-License-Identifier: LGPL-3.0-or-later
66#
7- # Last Updated: 6-01 -2026
7+ # Last Updated: 6-03 -2026
88
99"""Rohde and Schwarz Converter"""
1010
1818
1919from datetime import datetime , timedelta , timezone
2020from pathlib import Path
21- from typing import List , Optional , Tuple
21+ from typing import Optional , Tuple
2222
2323import numpy as np
2424
@@ -123,22 +123,19 @@ def validate_rohdeschwarz(xml_path: Path) -> None:
123123 tree = parse (xml_path )
124124 root = tree .getroot ()
125125
126- # validate CenterFrequency
127- center_freq_raw = _text_of (root , "Clock" )
128- try :
129- center_frequency = float (center_freq_raw )
130- except (TypeError , ValueError ) as err :
131- raise SigMFConversionError (f"Invalid or missing CenterFrequency: { center_freq_raw } " ) from err
132-
133- # validate SampleRate
126+ # validate (number of) Samples
134127 num_samples_raw = _text_of (root , "Samples" )
135128 try :
136- sample_rate = float (num_samples_raw )
129+ num_samples = float (num_samples_raw )
137130 except (TypeError , ValueError ) as err :
138- raise SigMFConversionError (f"Invalid or missing SampleRate : { num_samples_raw } " ) from err
131+ raise SigMFConversionError (f"Invalid or missing Number Of SamplesleRate Raw : { num_samples_raw } Converted to Float: { num_samples } " ) from err
139132
140- if sample_rate <= 0 :
141- raise SigMFConversionError (f"Invalid SampleRate: { sample_rate } (must be > 0)" )
133+ # Validate sample rate - "Clock"
134+ sample_rate_raw = _text_of (root , "Clock" )
135+ if float (sample_rate_raw ) <= 0 :
136+ raise SigMFConversionError (f"Invalid SampleRate: { sample_rate_raw } (must be > 0)" )
137+ if sample_rate_raw is None :
138+ raise SigMFConversionError ("Missing Sammple Rate (Clock) in rohdeschwarz XML" )
142139
143140 # validate ScalingFactor, for example, "1"
144141 scaling_factor_raw = _text_of (root , "ScalingFactor" )
@@ -167,7 +164,7 @@ def validate_rohdeschwarz(xml_path: Path) -> None:
167164 if numberofchannels_raw is None :
168165 # Missing NumberOfChannels in rohdeschwarz XML so use 1
169166 numberofchannels_raw = 1
170-
167+
171168 # validate associated IQ file exists - example IQ file name "File.complex.1ch.float32"
172169 datafilename_raw = _text_of (root , "DataFilename" )
173170 if datafilename_raw is None :
@@ -215,9 +212,9 @@ def _build_metadata(xml_path: Path) -> Tuple[dict, dict, list, int]:
215212 # validate required fields and associated IQ file
216213 validate_rohdeschwarz (xml_path )
217214
218- # extract and convert required fields
215+ # extract and convert required fields that were previously validated
219216
220- # TODO: R&S files don't seem to have a center frequency field, so maybe add a comment about this being an Oscilloscope capture.
217+ # TODO: R&S files don't have a center frequency field, so maybe add a comment about this being an SA or Oscilloscope capture.
221218 center_frequency = float ("0" )
222219
223220 numberofchannels_raw = _text_of (root , "NumberOfChannels" )
@@ -229,7 +226,6 @@ def _build_metadata(xml_path: Path) -> Tuple[dict, dict, list, int]:
229226 numberofchannels = int (numberofchannels_raw )
230227
231228 sample_rate = float (_text_of (root , "Clock" ))
232-
233229 data_type_raw = _text_of (root , "DataType" )
234230
235231 # optional EpochNanos field
@@ -265,14 +261,6 @@ def _build_metadata(xml_path: Path) -> Tuple[dict, dict, list, int]:
265261 except ValueError :
266262 log .warning (f"could not parse DataFileName: { datafilename_raw } " )
267263
268- scale_factor = None
269- scale_factor_raw = _text_of (root , "ScaleFactor" )
270- if scale_factor_raw :
271- try :
272- scale_factor = float (scale_factor_raw )
273- except ValueError :
274- log .warning (f"could not parse ScaleFactor: { scale_factor_raw } " )
275-
276264 # parse optional preview data if present
277265 preview_node = root .find (".//PreviewData" )
278266 if preview_node is not None :
@@ -310,10 +298,17 @@ def _build_metadata(xml_path: Path) -> Tuple[dict, dict, list, int]:
310298 elem_size = np .dtype (np .float32 ).itemsize
311299 frame_bytes = 2 * elem_size # I and Q components
312300
301+ #TODO: Test and validate
302+ sample_count = _text_of (root , "Samples" )
303+ log .debug ("sample count: %d" , sample_count )
304+
313305 # calculate sample count using the original IQ data file size
314306 sample_count_calculated = filesize // frame_bytes
315307 log .debug ("sample count: %d" , sample_count_calculated )
316308
309+ if sample_count != sample_count_calculated :
310+ log .debug ("sample counts not equal" )
311+
317312 # convert the datetime object to an ISO 8601 formatted string if EpochNanos is present
318313 iso_8601_string = None
319314 if epoch_nanos is not None :
0 commit comments