From 63e6ed22318dec869950971f210186f75a90b4a4 Mon Sep 17 00:00:00 2001 From: Krzysztof Rosinski Date: Wed, 14 Oct 2026 07:13:32 +0200 Subject: [PATCH] docs: simplify Touchstone example around the file reference --- CHANGELOG.md | 4 +++ docs/guide/touchstone.md | 37 +++++++++++----------- examples/README.md | 2 +- examples/index.html | 2 +- examples/touchstone/index.html | 11 ++----- examples/touchstone/main.ts | 56 ++++++++++++++++++---------------- tests/browser/examples.spec.ts | 5 ++- 7 files changed, 59 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe30b44..99311f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Unreleased + +- Simplify the Touchstone integration example to use the file reference for rendering and export. Remove its reference selector and renormalization, and clarify the basic import flow in the guide. The public API is unchanged. + ## 0.7.0 — 2026-10-14 - **Breaking:** group trace style options and snapshots into `line: { width, tolerancePx }` and `point: { radius }`. Add `TraceStyleOptions` for nested partial patches, reject unknown keys, and return detached readonly style snapshots. diff --git a/docs/guide/touchstone.md b/docs/guide/touchstone.md index ca33be3..89204b1 100644 --- a/docs/guide/touchstone.md +++ b/docs/guide/touchstone.md @@ -7,7 +7,7 @@ group: Guides Reference: {@link Touchstone}, {@link TouchstoneParseOptions}, {@link TouchstoneWriteOptions}. -## Touchstone import and export +## Import using the file reference `Touchstone.parse(text, options?)` returns `{ samples, referenceImpedanceOhms }`. It reads Touchstone 1.x S-parameters, converts RI/MA/DB into Cartesian Γ and @@ -30,13 +30,16 @@ async function showMeasurement(file: File): Promise { parameter: ports === 2 ? 'S22' : 'S11', output: 'packed', }); - const chart = new Smith({ referenceImpedanceOhms }); - chart.draw('#smith'); + const chart = new Smith('#smith', { referenceImpedanceOhms }); chart.addTrace(samples, { name: file.name }); return chart; } ``` +**The file already specifies its reference impedance.** Use the returned +`referenceImpedanceOhms` to configure the chart, as above. No renormalization is +needed. + Packed parsing writes directly into growing typed storage, without creating an object or coordinate array per sample. It scans lines incrementally within the supplied string; this is not a streaming file API. The returned buffer has exact @@ -51,6 +54,8 @@ per-port/complex reference impedances, noise blocks and Touchstone 2.x keywords are rejected. See the [IBIS Touchstone specification](https://www.ibis.org/touchstone_ver2.1/touchstone_ver2_1.pdf) for the legacy 1.x data layout. +## Export a one-port file + `Touchstone.stringify(samples, { referenceImpedanceOhms })` returns `.s1p` text with a `# Hz S RI R …` header and a final newline. It accepts object samples, tuples, or packed triples, writes numeric values without a precision limit, and @@ -60,25 +65,21 @@ reference impedance, and duplicate or descending frequencies throw `RangeError`. Samples are never silently sorted or discarded. ```ts -import { RfCalculations, Touchstone } from 'smithkit'; - -const sourceText = '# GHz S RI R 50\n1 0 0\n2 0.5 0'; -const parsed = Touchstone.parse(sourceText, { output: 'packed' }); -const samples = RfCalculations.renormalizeSamples( - parsed.samples, - parsed.referenceImpedanceOhms, - 75, -); -const text = Touchstone.stringify(samples, { referenceImpedanceOhms: 75 }); +import { Touchstone } from 'smithkit'; + +const sourceText = '# GHz S RI R 75\n1 0.2 -0.3\n2 0.2 0.3'; +const { samples, referenceImpedanceOhms } = Touchstone.parse(sourceText); +const text = Touchstone.stringify(samples, { referenceImpedanceOhms }); // Save text as measurement.s1p in your application. ``` -For an extracted S11/S22 trace, this is **one-port renormalization**: the other -port remains terminated in the original file reference. It is not renormalization -of the complete two-port network. Exporting S22 to `.s1p` represents that selected -port as the single port of the new file; transmission data is not exported. +When you intentionally need a different reference, use the separate +[reference impedance conversion API](rf.md#reference-impedance-and-renormalization). It is not needed +for loading a file at its original reference. Exporting S22 to `.s1p` represents +that selected port as the single port of the new file; transmission data is not +exported. The [Touchstone example](https://rosek86.github.io/smithkit/examples/touchstone/index.html) -shows parameter selection, packed import, renormalization and download. In the demo, +shows parameter selection, packed import at the file reference, and download. In the demo, choose **Two-port reflection** before importing `.s2p`; the trace name includes the selected parameter. Both `.s1p` and `.s2p` use packed import. diff --git a/examples/README.md b/examples/README.md index fd9d97c..223efc2 100644 --- a/examples/README.md +++ b/examples/README.md @@ -9,7 +9,7 @@ the TypeScript it executes, rather than a separately maintained snippet. | [Static chart](static/main.ts) | constructor options, `draw`, grid detail, traces | | [External marker controls](markers/main.ts) | stable marker IDs, `onEvent`, sample selection, focus | | [Themes and overrides](appearance/main.ts) | `setOptions`, presets, overrides | -| [Touchstone](touchstone/main.ts) | S11/S22 packed import, one-port renormalization, `.s1p` download | +| [Touchstone](touchstone/main.ts) | S11/S22 packed import, file reference, `.s1p` download | | [Report export](export/main.ts) | SVG/PNG, image size, background, marker legends | | [Mount, update, and destroy](basic/main.ts) | subscriptions, data replacement, resize, cleanup | | [React component](react/SmithChart.tsx) | effects, immutable props, events, StrictMode cleanup | diff --git a/examples/index.html b/examples/index.html index 1eeb7ed..3ca7ea5 100644 --- a/examples/index.html +++ b/examples/index.html @@ -39,7 +39,7 @@

One example, one task.

>

Touchstone

-

Read S11 or S22 into packed samples, renormalize, and download a one-port file.

+

Read S11 or S22 using the file reference and download a one-port file.

Open example →

SMITHKIT EXAMPLES

Touchstone

-

Extract S11 or S22, renormalize the reflection trace, and download a one-port file.

+

Read S11 or S22 using the file’s reference impedance and download a one-port file.

@@ -24,17 +24,12 @@

Touchstone

- -

- The other port remains terminated in the source file’s 50 Ω reference. This is one-port - renormalization, not a conversion of the full two-port network. + The chart uses the reference impedance from the file header. The selected reflection is + displayed and exported without conversion.

diff --git a/examples/touchstone/main.ts b/examples/touchstone/main.ts index 5768bf7..286dec2 100644 --- a/examples/touchstone/main.ts +++ b/examples/touchstone/main.ts @@ -1,46 +1,48 @@ -import { Smith, Touchstone, RfCalculations } from 'smithkit'; +import { Smith, Touchstone } from 'smithkit'; // Touchstone 1.x two-port order: frequency, S11, S21, S12, S22. const source = `! Synthetic two-port measurement -# GHz S RI R 50 +# GHz S RI R 75 1 0.4 -0.4 0.8 0 0.1 0 0.2 -0.3 1.5 0.0 0.0 0.9 0 0.1 0 0.1 0.0 2 0.4 0.4 0.8 0 0.1 0 0.2 0.3 `; -const chart = new Smith(); -chart.draw('#chart'); -let traceId: string | undefined; -let samples: Float64Array = new Float64Array(); const parameter = document.querySelector('#parameter')!; -const reference = document.querySelector('#reference')!; const status = document.querySelector('#status')!; -function update(): void { - const selected = parameter.value === 'S22' ? 'S22' : 'S11'; - const parsed = Touchstone.parse(source, { ports: 2, parameter: selected, output: 'packed' }); - const referenceImpedanceOhms = Number(reference.value); - samples = RfCalculations.renormalizeSamples( - parsed.samples, - parsed.referenceImpedanceOhms, - referenceImpedanceOhms, - ); - if (traceId) { - chart.removeTrace(traceId); - } - chart.setOptions({ referenceImpedanceOhms }); - traceId = chart.addTrace(samples, { name: selected, mode: 'both' }); - status.textContent = `${selected}: ${samples.length / 3} packed samples at ${referenceImpedanceOhms} Ω.`; +function readMeasurement() { + return Touchstone.parse(source, { + ports: 2, + parameter: parameter.value === 'S22' ? 'S22' : 'S11', + output: 'packed', + }); } -parameter.addEventListener('change', update); -reference.addEventListener('change', update); -update(); + +let measurement = readMeasurement(); +const chart = new Smith('#chart', { + referenceImpedanceOhms: measurement.referenceImpedanceOhms, +}); +const traceId = chart.addTrace(measurement.samples, { name: parameter.value, mode: 'both' }); + +function showStatus(): void { + status.textContent = `${parameter.value}: ${measurement.samples.length / 3} packed samples at ${measurement.referenceImpedanceOhms} Ω.`; +} +parameter.addEventListener('change', () => { + measurement = readMeasurement(); + chart.updateTrace(traceId, measurement.samples); + chart.setTraceOptions(traceId, { name: parameter.value }); + showStatus(); +}); +showStatus(); document.querySelector('#download')!.addEventListener('click', () => { - const text = Touchstone.stringify(samples, { referenceImpedanceOhms: Number(reference.value) }); + const text = Touchstone.stringify(measurement.samples, { + referenceImpedanceOhms: measurement.referenceImpedanceOhms, + }); const url = URL.createObjectURL(new Blob([text], { type: 'text/plain' })); const link = document.createElement('a'); link.href = url; - link.download = `${parameter.value}-${reference.value}ohm.s1p`; + link.download = `${parameter.value}-${measurement.referenceImpedanceOhms}ohm.s1p`; document.body.append(link); link.click(); link.remove(); diff --git a/tests/browser/examples.spec.ts b/tests/browser/examples.spec.ts index 8ead6c1..5be7ebe 100644 --- a/tests/browser/examples.spec.ts +++ b/tests/browser/examples.spec.ts @@ -276,12 +276,11 @@ test('large-trace example switches to one million samples, compares detail and r await page.screenshot({ path: 'test-results/examples-large-trace.png', fullPage: true }); }); -test('Touchstone example downloads the selected, renormalized reflection in s1p format', async ({ +test('Touchstone example preserves the file reference when displaying and exporting a selected reflection', async ({ page, }) => { await page.goto('examples/touchstone/index.html'); await page.getByLabel('Reflection parameter').selectOption('S22'); - await page.getByLabel('Trace reference').selectOption('75'); await expect(page.locator('#status')).toHaveText('S22: 3 packed samples at 75 Ω.'); const downloading = page.waitForEvent('download'); await page.getByRole('button', { name: 'Download .s1p' }).click(); @@ -293,7 +292,7 @@ test('Touchstone example downloads the selected, renormalized reflection in s1p expect(lines).toHaveLength(4); const [frequency, re, im] = lines[2].split(' ').map(Number); expect(frequency).toBe(1.5e9); - expect(re).toBeCloseTo((0.1 - 0.2) / (1 - 0.2 * 0.1), 14); + expect(re).toBe(0.1); expect(im).toBe(0); await page.screenshot({ path: 'test-results/examples-touchstone.png', fullPage: true }); });