rf-touchstone 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,22 +31,22 @@ import { Touchstone } from 'rf-touchstone'
31
31
  import { abs, arg, pi, complex } from 'rf-touchstone'
32
32
  ```
33
33
 
34
- ## Core Concepts
35
-
36
- ### 1. **Touchstone Class** - Main API Entry Point
34
+ ## Touchstone Class
37
35
 
38
36
  The `Touchstone` class is the primary interface for working with .snp files.
39
37
 
40
- #### Creating Touchstone Objects
38
+ ### Creating Touchstone Objects
41
39
 
42
40
  **From URL (Browser or Node.js with fetch):**
43
41
 
44
42
  ```typescript
45
43
  // Auto-detect nports from filename (.s2p → 2-port)
46
44
  const ts = await Touchstone.fromUrl('https://example.com/device.s2p')
45
+ console.log(ts.name) // 'device' - automatically extracted from filename
47
46
 
48
47
  // Explicit nports if filename doesn't indicate
49
48
  const ts = await Touchstone.fromUrl('https://example.com/data.txt', 2)
49
+ console.log(ts.name) // 'data' - basename without extension
50
50
  ```
51
51
 
52
52
  **From File Object (Browser file input):**
@@ -55,6 +55,7 @@ const ts = await Touchstone.fromUrl('https://example.com/data.txt', 2)
55
55
  // In any framework with file input
56
56
  const handleFileUpload = async (file: File) => {
57
57
  const touchstone = await Touchstone.fromFile(file)
58
+ console.log(touchstone.name) // Filename without extension
58
59
  // Use touchstone object
59
60
  }
60
61
  ```
@@ -71,16 +72,17 @@ const s2pContent = `! 2-port S-parameter data
71
72
  2.0 0.45 -60 0.90 15 0.10 80 0.55 -45
72
73
  3.0 0.40 -75 0.85 20 0.15 75 0.50 -60`
73
74
 
74
- // Parse the text content
75
- const touchstone = Touchstone.fromText(s2pContent, 2) // 2 = 2-port network
75
+ // Parse the text content with optional name
76
+ const touchstone = Touchstone.fromText(s2pContent, 2, 'my_measurement') // 2 = 2-port network
76
77
 
77
78
  // Now you can use the parsed data
79
+ console.log(touchstone.name) // 'my_measurement'
78
80
  console.log(touchstone.frequency.f_scaled) // [1.0, 2.0, 3.0]
79
81
  console.log(touchstone.format) // 'MA'
80
82
  console.log(touchstone.parameter) // 'S'
81
83
  ```
82
84
 
83
- ### 2. **Accessing Touchstone Data**
85
+ ### Accessing Touchstone Data
84
86
 
85
87
  ```typescript
86
88
  const ts = await Touchstone.fromUrl('device.s2p')
@@ -89,6 +91,10 @@ const ts = await Touchstone.fromUrl('device.s2p')
89
91
  const frequencies = ts.frequency.f_scaled // Array of numbers in specified unit
90
92
  const unit = ts.frequency.unit // 'Hz' | 'kHz' | 'MHz' | 'GHz'
91
93
 
94
+ // Name property (automatically extracted from filename or manually set)
95
+ const name = ts.name // e.g., 'device' (without extension)
96
+ ts.name = 'modified_device' // Can be modified for plot legends, filenames, etc.
97
+
92
98
  // Options line data
93
99
  const format = ts.format // 'RI' | 'MA' | 'DB'
94
100
  const parameter = ts.parameter // 'S' | 'Y' | 'Z' | 'G' | 'H'
@@ -100,7 +106,7 @@ const nports = ts.nports // Number of ports (1, 2, 3, 4, etc.)
100
106
  const matrix = ts.matrix // Complex number matrix
101
107
  ```
102
108
 
103
- ### 3. **Understanding Matrix Indexing** ⚠️ CRITICAL
109
+ ### Understanding Matrix Indexing ⚠️ CRITICAL
104
110
 
105
111
  **Matrix Structure:**
106
112
 
@@ -133,7 +139,7 @@ const s12 = ts.matrix[0][1][freqIdx] // S12
133
139
  // General pattern: Sij = ts.matrix[i-1][j-1][freqIdx]
134
140
  ```
135
141
 
136
- ### 4. **Format Conversion**
142
+ ### Format Conversion
137
143
 
138
144
  To convert between formats (RI, MA, DB):
139
145
 
@@ -149,7 +155,7 @@ const dbContent = ts.writeContent() // Generate new file content
149
155
  const dbTs = Touchstone.fromText(dbContent, ts.nports)
150
156
  ```
151
157
 
152
- ### 5. **Writing Touchstone Content**
158
+ ### Writing Touchstone Content
153
159
 
154
160
  ```typescript
155
161
  const ts = await Touchstone.fromUrl('device.s2p')
@@ -170,7 +176,7 @@ import fs from 'fs/promises'
170
176
  await fs.writeFile('modified-device.s2p', content)
171
177
  ```
172
178
 
173
- ### 6. **Working with Complex Numbers**
179
+ ### Working with Complex Numbers
174
180
 
175
181
  The library uses mathjs Complex type `{ re: number, im: number }`:
176
182
 
@@ -193,6 +199,114 @@ const magnitudeDB = 20 * Math.log10(magnitude)
193
199
  const phaseDegrees = (phase * 180) / pi
194
200
  ```
195
201
 
202
+ ## Frequency Class
203
+
204
+ The `Frequency` class provides powerful utilities for unit conversion and wavelength calculations. While it's typically accessed through `touchstone.frequency`, you can also work with it directly.
205
+
206
+ ### Accessing Frequency Data
207
+
208
+ ```typescript
209
+ const ts = await Touchstone.fromUrl('device.s2p')
210
+
211
+ // Access frequency points in the file's original unit
212
+ const frequencies = ts.frequency.f_scaled // e.g., [1.0, 2.0, 3.0]
213
+ const unit = ts.frequency.unit // e.g., 'GHz'
214
+
215
+ // Get frequency points in different units
216
+ const freqsInHz = ts.frequency.f_Hz // [1e9, 2e9, 3e9]
217
+ const freqsInMHz = ts.frequency.f_MHz // [1000, 2000, 3000]
218
+ const freqsInGHz = ts.frequency.f_GHz // [1.0, 2.0, 3.0]
219
+ ```
220
+
221
+ ### Converting Frequency Units
222
+
223
+ ```typescript
224
+ const ts = await Touchstone.fromUrl('device.s2p')
225
+
226
+ // Get current unit
227
+ console.log(ts.frequency.unit) // 'GHz'
228
+ console.log(ts.frequency.f_scaled) // [1.0, 2.0, 3.0]
229
+
230
+ // Change unit - automatically rescales f_scaled
231
+ ts.frequency.unit = 'MHz'
232
+ console.log(ts.frequency.f_scaled) // [1000, 2000, 3000]
233
+
234
+ // Access in any unit without changing internal representation
235
+ const inHz = ts.frequency.f_Hz // [1e9, 2e9, 3e9]
236
+ const inTHz = ts.frequency.f_THz // [0.001, 0.002, 0.003]
237
+ ```
238
+
239
+ > [!IMPORTANT]
240
+ > **THz Support**: While THz can be accessed programmatically via `f_THz` getter/setter, it is **not** an official unit in Touchstone v1.x/v2.x file formats. Do not set `frequency.unit = 'THz'` as it will throw an error. THz is only available through the `f_THz` property for conversion purposes.
241
+
242
+ ### Working with Wavelength
243
+
244
+ The `Frequency` class can convert between frequency and wavelength using the relationship $\lambda = c/f$ where $c$ is the speed of light (299,792,458 m/s).
245
+
246
+ ```typescript
247
+ const ts = await Touchstone.fromUrl('device.s2p')
248
+
249
+ // Get wavelengths in different units
250
+ const wavelengthsInM = ts.frequency.wavelength_m // meters
251
+ const wavelengthsInCm = ts.frequency.wavelength_cm // centimeters
252
+ const wavelengthsInMm = ts.frequency.wavelength_mm // millimeters
253
+ const wavelengthsInUm = ts.frequency.wavelength_um // micrometers
254
+ const wavelengthsInNm = ts.frequency.wavelength_nm // nanometers
255
+
256
+ // Example: 1 GHz → λ ≈ 0.3 m = 30 cm = 300 mm
257
+ ```
258
+
259
+ ### Setting Frequency from Wavelength
260
+
261
+ You can also set frequency points by specifying wavelengths. This is bidirectional - setting wavelength updates the underlying frequency data:
262
+
263
+ ```typescript
264
+ import { Frequency } from 'rf-touchstone'
265
+
266
+ const freq = new Frequency()
267
+ freq.unit = 'GHz'
268
+
269
+ // Set frequencies using wavelength in millimeters
270
+ // For λ = 300 mm → f ≈ 1 GHz
271
+ // For λ = 150 mm → f ≈ 2 GHz
272
+ freq.wavelength_mm = [300, 150, 100]
273
+
274
+ console.log(freq.f_GHz) // [~1.0, ~2.0, ~3.0]
275
+ console.log(freq.f_scaled) // [~1.0, ~2.0, ~3.0]
276
+ ```
277
+
278
+ ### Practical Example: Frequency Range Analysis
279
+
280
+ ```typescript
281
+ async function analyzeFrequencyRange(file: File) {
282
+ const ts = await Touchstone.fromFile(file)
283
+
284
+ const freqs = ts.frequency.f_GHz
285
+ const wavelengths = ts.frequency.wavelength_mm
286
+
287
+ return {
288
+ numPoints: freqs.length,
289
+ range: {
290
+ frequency: {
291
+ min: freqs[0],
292
+ max: freqs[freqs.length - 1],
293
+ unit: 'GHz',
294
+ },
295
+ wavelength: {
296
+ min: wavelengths[wavelengths.length - 1], // shortest
297
+ max: wavelengths[0], // longest
298
+ unit: 'mm',
299
+ },
300
+ },
301
+ // Calculate frequency spacing
302
+ spacing:
303
+ freqs.length > 1
304
+ ? ((freqs[freqs.length - 1] - freqs[0]) / (freqs.length - 1)).toFixed(3)
305
+ : 'N/A',
306
+ }
307
+ }
308
+ ```
309
+
196
310
  ## Common Use Cases
197
311
 
198
312
  ### Example 1: File Upload in Browser (Vanilla JavaScript)
@@ -405,6 +519,7 @@ function downloadFile() {
405
519
  // Touchstone class
406
520
  class Touchstone {
407
521
  // Properties
522
+ name?: string // Filename without extension, used for legends and default filenames
408
523
  nports?: number
409
524
  frequency?: Frequency
410
525
  format?: 'RI' | 'MA' | 'DB'
@@ -414,10 +529,11 @@ class Touchstone {
414
529
  comments: string[]
415
530
 
416
531
  // Static methods
417
- static fromText(content: string, nports: number): Touchstone
532
+ static fromText(content: string, nports: number, name?: string): Touchstone
418
533
  static fromUrl(url: string, nports?: number): Promise<Touchstone>
419
534
  static fromFile(file: File, nports?: number): Promise<Touchstone>
420
535
  static getFilename(pathOrUrl: string): string
536
+ static getBasename(filenameOrPath: string): string
421
537
  static parsePorts(filename: string): number | null
422
538
 
423
539
  // Instance methods
@@ -1,14 +1,14 @@
1
1
  <svg width="103.3" height="20" viewBox="0 0 1033 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="coverage: 100%">
2
2
  <title>coverage: 100%</title>
3
- <linearGradient id="dtDeG" x2="0" y2="100%">
3
+ <linearGradient id="cFjNt" x2="0" y2="100%">
4
4
  <stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
5
5
  <stop offset="1" stop-opacity=".1"/>
6
6
  </linearGradient>
7
- <mask id="LuLjj"><rect width="1033" height="200" rx="30" fill="#FFF"/></mask>
8
- <g mask="url(#LuLjj)">
7
+ <mask id="ZbOuS"><rect width="1033" height="200" rx="30" fill="#FFF"/></mask>
8
+ <g mask="url(#ZbOuS)">
9
9
  <rect width="603" height="200" fill="#555"/>
10
10
  <rect width="430" height="200" fill="#49c31a" x="603"/>
11
- <rect width="1033" height="200" fill="url(#dtDeG)"/>
11
+ <rect width="1033" height="200" fill="url(#cFjNt)"/>
12
12
  </g>
13
13
  <g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
14
14
  <text x="60" y="148" textLength="503" fill="#000" opacity="0.25">coverage</text>