Repository navigation
analog M5: waveforms as ngspice RAW files that uberWAVE opens -- raw_writer.t27 checked against ngspice and uberWAVE's parser (Closes #10909) - #10940
Merged
Conversation
…writer.t27, checked against ngspice and uberWAVE's parser (Closes #10909) specs/analog/raw_writer.t27 writes the ngspice RAW file (ASCII and binary) for a time-major f64 trace, with the variable table and the Date line as parameters, and raw_check reads a file back and refuses one whose header lies about its points or variables. The layout was read off ngspice-47 itself: specs/analog/decks/raw_ref.cir writes one transient both ways and both files are embedded in the spec, so the writer's output must equal ngspice's bytes. The ASCII values are C's %.15e, built from the exact decimal expansion of the double (not f64 arithmetic), checked against 35 printf vectors with ties, carries and subnormals. tri raw writes the M1 RLC trace (linear.t27 circuit 2, the fold equals the pinned RLC_EXP_S) as such a file; ngspice loads it and prints the same samples, and uberWAVE's wp2-parser reads names, 201 points and the values (binary bit for bit, ASCII to 4.4e-16 relative). Hand Rust in this commit: +15 lines in cli/tri/src/main.rs, -23 (a dead function, extract_rx in cli/dlc10, unreferenced) in cli/dlc10/src/lib.rs. gen-rust cannot lower @bitcast (#10920), so the f64 <-> bits pair is arithmetic. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Contributor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #10909. Part of #10486 (M5, first slice).
What this adds
specs/analog/raw_writer.t27(moduleAnalogRawWriter): writes the ngspice RAW file, ASCII and binary, for a time-major f64 trace;raw_checkis the reader that judges a file. 18 tests.specs/analog/decks/raw_ref.cir: the deck whosewriteoutput (ASCII and binary, ngspice-47) is the reference the writer must equal. Both files are embedded in the spec.tri raw <out.raw> [--binary] [--date ...]: writes the M1 RLC trace (circuit 2 oflinear.t27) as such a file. Glue only; every rule is the spec (gen/rust/analog/raw_writer.rsist27c gen-rustof it, byte-identical)..trinity/seals/analog_AnalogRawWriter.json. Noanalog_AnalogSar*seal and nosar_*/mos_*spec is touched.The format, read off ngspice-47 (FR-001)
Header lines: Title, Date, Command (optional), Plotname,
Flags: real,No. Variables: N,No. Points: P,Variables:, N lines<TAB>index<TAB>name<TAB>type, thenValues:orBinary:. ASCII point:index<TAB>v0, then<TAB>vjfor each other variable (one per line), then an empty line, every value C's%.15e. Binary point: N little-endian f64.Three things the reference taught that a manual would not have:
9,10,100,1000), not a padded field.Command:is a command that ngspice executes when it loads the file (misplaced Command: line,AnalogRawWriter: no such command available in ngspice). Files written here carry none. ngspice's ownCommand: ngspice-47, Buildis the one text it accepts; the reference test still writes it, to match the bytes.ngspice -rpads the point count with spaces after a run (No. Points: 220); the reader accepts that.%.15eneeds 16 significant digits of the exact binary value, rounded to nearest, ties to even. f64 arithmetic cannot do that, so the digits come from the exact decimal expansion of the double (base-1e9 limbs, at most 767 digits). The f64 <-> bits pair is built from arithmetic too, because gen-rust prints@bitCastas written and rustc refuses it (filed: #10920).Tests (
t27c test-report specs/analog/raw_writer.t27)%.15eequals Python 3's'%.15e' % xon 35 vectors: round numbers, 1e-11 (just below the decimal), 1e23, exact ties that round down, up and carry (3000000000000000.5,...1.5,3999999999999999.5), subnormals, the smallest normal, the largest double, a dozen random ones.SHORT/TRAIL, ASCII and binary), one variable too many or too few (VARS/MODE), a body with 3 or 5 values per point against 4 variables (SHAPE), a wrong index, a broken value, a missing flags line, a missing mode line, a binary file one byte short or long.RLC_EXP_S, whichlinear.t27pins, so it is that simulation; a trace with one stored constant's sign flipped is not. Both files passraw_checkand the binary decodes exactly.t27b teston a copy, deleted afterwards): A no space before the index (6 tests fail), B ties round up instead of to even (1), C big-endian binary (2), D point count one too small (6), E truncation instead of rounding (2).FR-002: ngspice loads the file, uberWAVE's parser reads it
The file comes from the merged cell, written by the committed command (debug build of
trifrom this branch):ngspice-47 (
loadthenprint, both modes;load.ciris a 5-line.controldeck, not committed):The binary file prints the same numbers. The spec's own value for
v(2)at point 1 is0.002375304698944092, at point 1001.0759003162384033(the capacitor rings past 1 V, damping 0.5). Rewritten by ngspice (load, thenwrite ... allas binary) and compared with a scratch script (not committed): from the binary file bit-exact, from the ASCII file at most 4.4e-16 relative, which is the 16 digits of%.15e.uberWAVE
wp2-parser(GPL-2.0, commitc75a89c8f; its five source files fetched through the GitLab API into a scratch directory, built there withclang++ -std=c++20 -O1 -Iinclude main.cpp src/parser.cpp, deleted afterwards, never vendored):A short scratch C++ driver over
RawFileParser::getColumnprinted every column with%.17g: namestime v(in) v(1) v(2) i(l1), 201 points each; the binary file's 1005 values are bit-exact with ours, the ASCII file's within 4.4e-16 relative.Negative control (header says 202 or 200 points, 201 present): uberWAVE refuses 202 (
Parsed rows 201 does not equal expected 202,Parsing failed) but reads 200 without complaint; ngspice reportsError: unable to read point countfor 202 (and still builds a 202-long plot) andError: strange line in rawfile:for 200 (no plot is loaded). The spec'sraw_checkrefuses both (SHORT,TRAIL). Two observations for Symbiotic EDA, from this run only:uwparser --preview Nstreams a binary file as text (Skipped non-numeric token) for ngspice's own binary file as well as ours, while the full parse reads both; and a declared count smaller than the data is accepted.FR-003: hand lines (own-language budget)
git diff --numstat:cli/tri/src/main.rs+15 -0 (amodpair, oneCommandsvariant, one dispatch arm,cmd_raw: allocate four buffers, callraw_rlc_file, write the file),cli/dlc10/src/lib.rs+0 -23. Net hand lines -8. The 23 deleted lines areextract_rxwith its doc comment and#[allow(dead_code)]:git grep -nw extract_rxmatched only its definition, and thedlc10tests still compile (cargo test -p dlc10 --no-run).gen/rust/analog/raw_writer.rs(1025 lines) is generated and force-added, like the other tracked gen files; it ist27c gen-rustoutput,cmp-identical on regeneration. I did not touchcmd_t27o.Gates run
t27c test-report: 18/18, 0 vacuous (above).t27b test: 18/18.t27c seal specs/analog/raw_writer.t27 --savethen--verify: all hashes MATCH (closure:analog/linear.t27).tri types ratchet:RATCHET: CLEAN(struct namesRawPartsandRawInfoare specific).python3 -I tools/dupe_scan.py: no new duplicate body.tools/check_documented_commands_exist.pywith a freshly builttri: 138 dead mentions, the recorded ceiling (the staletarget/release/trireads 140, which is not from this change).gen-rustoutput is from thetarget/release/t27cof this checkout (0.5.2+ea35d9b72), which predates gen-rust: eight constructs that passed test-report now compile under rustc (Closes #8891) #9135 and [bug] t27c gen-rust: the use splice matches words inside string literals and pulls in a whole module (13,432 vs 4,111 lines) #10824. The spec avoids the constructs those changed (no local array passed to a mutable slice parameter, norunorstepword that would splice code fromlinear.t27), so the output should not move; if the seal'sgen_hash_rustdrifts under a fresh compiler, regenerate.What is not covered
nan,inf,-inf(ASCII) or the canonical pattern (binary).k * dt;decks/rlc_fixed.cirshifts its axis by 42.5 ns, so the two traces overlay after that shift. Nothing here compares our trace with ngspice's trace of the same circuit.raw_*_tracefunction) are the next slice.🤖 Generated with Claude Code