5
$\begingroup$

I have Spice simulation output file "Sim.txt". The data within is in a weird non-standard format (the two columns are '\t' separated):

Freq.   V(output)
1.00000000000000e+000   (7.99999776894160e+001dB,1.79999988069699e+002°)
1.12201845430196e+000   (7.99999776899954e+001dB,1.79999986613982e+002°)
1.25892541179417e+000   (7.99999776907247e+001dB,1.79999984980640e+002°)
1.41253754462275e+000   (7.99999776916429e+001dB,1.79999983148001e+002°)
1.58489319246111e+000   (7.99999776927988e+001dB,1.79999981091746e+002°)
1.77827941003892e+000   (7.99999776942540e+001dB,1.79999978784591e+002°)
1.99526231496888e+000   (7.99999776960861e+001dB,1.79999976195919e+002°)
2.23872113856834e+000   (7.99999776983925e+001dB,1.79999973291382e+002°)
2.51188643150958e+000   (7.99999777012960e+001dB,1.79999970032438e+002°)
2.81838293126445e+000   (7.99999777049514e+001dB,1.79999966375842e+002°)
...

How can I import this data into 3 respective lists?

Import["Sim.txt","Table"] imports the first column correctly, but the second and third are imported as one, as text I assume, with parenthesis and units and what not.

Is there a way to Import with a defined pattern? Or how would this be done?

$\endgroup$
  • $\begingroup$ Perhaps a combination of ReadLine, StringSplit, and ToExpression? Are the spaces between the first and second column just spaces, or a tab in the original file? Could you share a sample file (e.g. pastebin, or dropbox link, or similar)? $\endgroup$ – MarcoB Aug 22 '17 at 18:02
  • $\begingroup$ The units are volts, decibels, and degrees? $\endgroup$ – J. M. is away Aug 22 '17 at 18:03
  • $\begingroup$ Yes, those are the units. $\endgroup$ – A. Vieira Aug 22 '17 at 18:28
5
$\begingroup$

So, J.M.'s comment to one of the answers provided the clues to what is for me the most elegant solution:

Import["sim.txt","Table","FieldSeparators" -> {"\t(", "dB,", "°)"}, HeaderLines -> 1];

That does it. The data is correctly interpreted (exponentiation and all) into a 3 dimensional list.

The FieldSeparators I specify are different than his though. They are the 3 sequences of text that flank the numbers. Even the last "°)" characters are important so the last column is imported in good shape.

Thanks for all of your answers. I learned a lot.

$\endgroup$
  • $\begingroup$ Good work customizing my suggestion. ;) $\endgroup$ – J. M. is away Aug 22 '17 at 20:25
2
$\begingroup$

Another way to do it and get a Dataset.

dat = SemanticImport["Sim.txt", Automatic, "NamedColumns",HeaderLines -> 1];
import[dat_] := Module[{keys, val, sanitize},
   keys = First@StringSplit@Most@Keys@dat;
   val = Values[dat];
   sanitize = (Interpreter["Number"] /@StringSplit[
   (StringReplace[#,{")" -> "", "(" -> "","dB" -> "", "\[Degree]" -> ""}]), ","]) &;
   Transpose@
    Dataset@Association[
      Rule @@@ Transpose@{keys, { First@val, sanitize /@ Last[val]}}]
   ];
import@dat
$\endgroup$
2
$\begingroup$

Assuming input is a string containing the simulation output, you could do something like this:

StringCases[
  Shortest[a__] ~~ Whitespace ~~ "(" ~~ b__ ~~ "dB," ~~ c__ ~~ "°)" :> 
    Internal`StringToDouble /@ {a, b, c}
] /@ Rest@StringSplit[input, "\n"]

StringSplit breaks the string into lines. I am assuming that all line terminators are \n and not \r (pay attention to this). Rest throws away the first line. StringCases extracts the three values using string patterns. All those extra characters such as ( and dB make this easier.

Internal`StringToDouble is an undocumented function to parse e-notation numbers. Be careful: it doesn't detect incorrect syntax!

$\endgroup$
1
$\begingroup$

I would do :

sample="Freq.   V(output)
1.00000000000000e+000   (7.99999776894160e+001dB,1.79999988069699e+002\[Degree])
1.12201845430196e+000   (7.99999776899954e+001dB,1.79999986613982e+002\[Degree])
1.25892541179417e+000   (7.99999776907247e+001dB,1.79999984980640e+002\[Degree])
1.41253754462275e+000   (7.99999776916429e+001dB,1.79999983148001e+002\[Degree])
1.58489319246111e+000   (7.99999776927988e+001dB,1.79999981091746e+002\[Degree])
1.77827941003892e+000   (7.99999776942540e+001dB,1.79999978784591e+002\[Degree])
1.99526231496888e+000   (7.99999776960861e+001dB,1.79999976195919e+002\[Degree])
2.23872113856834e+000   (7.99999776983925e+001dB,1.79999973291382e+002\[Degree])
2.51188643150958e+000   (7.99999777012960e+001dB,1.79999970032438e+002\[Degree])
2.81838293126445e+000   (7.99999777049514e+001dB,1.79999966375842e+002\[Degree])";
Export["sample.txt",sample,"Text"]  

ReadList["sample.txt",Word,RecordLists->True,WordSeparators->{" ",","}] //
Map[StringReplace[#,{"("-> "",")"-> "","dB"-> "","Â\[Degree]"-> ""}]&,#,{2}]& //
Map[Internal`StringToDouble[#]&,#,{2}]& 

{{$Failed["Bad Format"], 0.}, {1., 80., 180.}, {1.12202, 80., 180.}, {1.25893, 80., 180.}, {1.41254, 80., 180.}, {1.58489, 80., 180.}, {1.77828, 80., 180.}, {1.99526, 80., 180.}, {2.23872, 80., 180.}, {2.51189, 80., 180.}, {2.81838, 80., 180.}}

Internal`StringToDouble is not documented. See here . You can instead use Import[..., "Table"] but it is very slow.

$\endgroup$
  • $\begingroup$ "Table" could still work: Import["Sim.txt", "Table", "FieldSeparators" -> {"(", ",", " ", ")"}, HeaderLines -> 1] /. x_String :> Internal`StringToDouble[First[StringSplit[x, {"dB", "°"}]]]. The OP can change to Quantity[] objects later if need be. $\endgroup$ – J. M. is away Aug 22 '17 at 18:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.