Skip to content

Initial commit of prototype converter for Rohde and Schwarz IQ.TAR - #144

Open
KelseyCreekSoftware wants to merge 17 commits into
sigmf:mainfrom
KelseyCreekSoftware:feature/rohdeschwarz
Open

Initial commit of prototype converter for Rohde and Schwarz IQ.TAR #144
KelseyCreekSoftware wants to merge 17 commits into
sigmf:mainfrom
KelseyCreekSoftware:feature/rohdeschwarz

Conversation

@KelseyCreekSoftware

Copy link
Copy Markdown
Contributor

@codacy-production

codacy-productionBot commented Apr 4, 2026

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues17 high

Alerts:
⚠ 17 issues (≤ 0 issues of at least minor severity)

Results:
17 new issues

CategoryResults
Security17 high

View in Codacy

🟢 Metrics90 complexity · 5 duplication

MetricResults
Complexity90
Duplication5

View in Codacy

TIP This summary will be updated as you push new changes. Give us feedback

@Teque5

Copy link
Copy Markdown
Collaborator

Before we get going on this Rohde & Swarz support, is pr #136 ready to merge? If so let's do that and then you can rebase this branch.

@KelseyCreekSoftware

Copy link
Copy Markdown
ContributorAuthor

Sure, that sounds like a good plan.
I think the Spike Signal Hound branch is ready to merge, but I'm just learning about the SigMF python library, so would defer to others.

@Teque5

Copy link
Copy Markdown
Collaborator

I merged the Signal Hound branch so you should be able to rebase this branch to main now.

Comment threadsigmf/convert/__main__.py Outdated
from . import detect_converter
from .blue import blue_to_sigmf
from .signalhound import signalhound_to_sigmf
from .signalhound import signalhound_to_sigmf

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

repeated line

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an initial Rohde & Schwarz IQ.TAR → SigMF conversion path to the sigmf.convert subsystem, wiring it into converter auto-detection and the sigmf_convert CLI, and introducing tests to validate key behaviors.

Changes:

  • Introduce sigmf/convert/rohdeschwarz.py implementing IQ.TAR extraction, XML parsing/validation, SigMF metadata construction, and dataset/archive/NCD writing.
  • Extend converter detection + CLI dispatch to recognize .tar IQ.TAR recordings and invoke the new converter.
  • Add unit tests covering XML-to-dict conversion, TAR extraction, validation failures, metadata building, IQ reading, and NCD creation.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 15 comments.

FileDescription
sigmf/convert/rohdeschwarz.pyNew Rohde & Schwarz IQ.TAR converter implementation (extraction, validation, metadata + data conversion, output writing).
sigmf/convert/__init__.pyExtend converter detection to recognize Rohde & Schwarz IQ.TAR and enhance magic-byte lookup.
sigmf/convert/__main__.pyWire the new converter into the unified conversion CLI.
tests/test_convert_rohdeschwarz.pyNew test suite for the Rohde & Schwarz converter.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadsigmf/convert/rohdeschwarz.py Outdated
Comment on lines +71 to +75
member_path = os.path.join(target_dir, member.name)
abs_target = os.path.abspath(target_dir)
abs_member = os.path.abspath(member_path)

return abs_member.startswith(abs_target)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Comment on lines +77 to +85
def safe_extract(tar, target_dir):
"""
Extract only safe members from a tarfile.
"""
for member in tar.getmembers():
if not is_safe_member(tar, member, target_dir):
raise Exception(f"Unsafe path detected in TAR: {member.name}")
tar.extract(member, target_dir)

Comment threadsigmf/convert/rohdeschwarz.py Outdated
Comment on lines +126 to +142
# validate CenterFrequency
center_freq_raw = _text_of(root, "Clock")
try:
center_frequency = float(center_freq_raw)
except (TypeError, ValueError) as err:
raise SigMFConversionError(f"Invalid or missing CenterFrequency: {center_freq_raw}") from err

# validate SampleRate
num_samples_raw = _text_of(root, "Samples")
try:
sample_rate = float(num_samples_raw)
except (TypeError, ValueError) as err:
raise SigMFConversionError(f"Invalid or missing SampleRate: {num_samples_raw}") from err

if sample_rate <= 0:
raise SigMFConversionError(f"Invalid SampleRate: {sample_rate} (must be > 0)")

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Comment on lines +338 to +347
# add optional rohdeschwarz-specific fields to global metadata using rohdeschwarz: namespace
# only include fields that aren't already represented in standard SigMF metadata
if scaling_factor:
global_md["rohdeschwarz:scaling_factor"] = scaling_factor
if datafilename:
global_md["rohdeschwarz:iq_datafilename"] = datafilename # provenance
if userdata:
global_md["rohdeschwarz:userdata"] = userdata #open ended field for user defined data.
if preview_data:
global_md["rohdeschwarz:preview_trace"] = preview_data

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to reflect when 0.0 would be appropriate based on current understanding of R&S data.

Comment threadsigmf/convert/rohdeschwarz.py Outdated
Comment on lines +468 to +470
# Get unique IQ filename from global_info
iq_filename = global_info.get("rohdeschwarz:iq_datafilename")
print(f"iq_filename: {iq_filename}")

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Comment on lines +104 to +115
elif file_path.suffix in [".tar"]:
# iq.tar file extensions are used by Rohde & Schwarz for their IQ data, but the .tar extension is also used by other formats.
# So parse the tar file to determine if it is a Rohde & Schwarz file or not.
rohde_schwarz_expanded_magic_bytes = get_magic_bytes(file_path, count=20, offset=0,magic_bytes=b"RS_IQ_TAR_FileFormat") # <RS_IQ_TAR_FileFormat>
if rohde_schwarz_expanded_magic_bytes == b"RS_IQ_TAR_FileFormat":
return "rohdeschwarz"
else:
raise SigMFConversionError(
f"Unsupported XML file format. Root element: {rohde_schwarz_expanded_magic_bytes}. "
f"Expected RS_IQ_TAR_FileFormat for IQ.TAR files."
)

Comment threadtests/test_convert_rohdeschwarz.py Outdated
Comment on lines +27 to +29
"""
Create a minimal, valid Rohde & Schwarz IQ.TAR file for testing.
"""

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Comment threadsigmf/convert/rohdeschwarz.py Outdated
Comment on lines +553 to +554
data_file_path = rohdeschwarz_path.parent / iq_filename
print(f"data_file_path: {data_file_path}")

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Comment on lines +542 to +545
output_dir = filenames["archive_fn"].parent
output_dir.mkdir(parents=True, exist_ok=True)
meta.tofile(filenames["archive_fn"], toarchive=True)
log.info("wrote SigMF archive to %s", filenames["archive_fn"])

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Comment on lines +581 to +583
# write metadata file
meta.tofile(filenames["meta_fn"], toarchive=False)
log.info("wrote SigMF metadata to %s", filenames["meta_fn"])

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@KelseyCreekSoftware

Copy link
Copy Markdown
ContributorAuthor

Need to update this PR to reflect all of the cool work going on in sigmf, including new use of Hypothesis.

@KelseyCreekSoftware
KelseyCreekSoftware marked this pull request as draft June 3, 2026 00:22
@KelseyCreekSoftware

Copy link
Copy Markdown
ContributorAuthor

I have updated the R&S tests to use hypothesis and have done additional testing to compare data rendered in one of the R&S IQ.tar file viewers. But still not sure when I compare the output, if the converter is handling the IQ data properly. There may be a fundamental error in my IQ conversion code that I cannot see. I do think that the XML looks OK, and the normal converter options seem to work as expected. So with those important disclaimers, I will remove the draft and request review.

@KelseyCreekSoftware

Copy link
Copy Markdown
ContributorAuthor

(Note that the failing test is related to the long runtime in the new test_siggen.py related to an unbounded hypothesis range)

@KelseyCreekSoftware
KelseyCreekSoftware marked this pull request as ready for review July 20, 2026 00:02
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@KelseyCreekSoftware@Teque5@777arc@aminalbaji2025-a11y