How to massage ocnPrint header line

Discussion in 'Cadence' started by Svenn Bjerkem, Sep 22, 2006.

  1. Hi,

    looking a bit around to see if I could find a way to get a bit more
    control over that first line that ocnPrint produces. In many cases I
    have only "getData(" in there. The interesting information in the
    string is towards the end where the variable name and the current value
    is listed.

    I also tried to use awvPrintWaveform, that give me a Result Display
    Window where I can use info show output to see the entire string that
    is cut of. This means that the info is available somewhere in the
    system.

    At the moment it is possible to write to a file, but cadence is able to
    print the data into the result browser so it should also be possible to
    print the info into a list, one list for each line, then it would be
    possible to replace the header line with values that are extracted with
    the famGetSweep* functions.

    The goal of this exercise is to be able to generate ascii data files
    for programs like gnuplot, kpl, qtiplot, hippodraw, veusz etc.without
    the empty lines and the difficult header line that ocnPrint generates.

    Maybe that nondescriptive heading line in ocnPrint is actually a bug in
    Cadence? Has anybody reported the behaviour as such? Would it help if I
    did?
     
    Svenn Bjerkem, Sep 22, 2006
    #1
  2. With the help from some examples that I found on comp.cad.cadence I put
    together this procedure to dump the contents of a one level family as
    an ascii file. I wanted to make a more general family flattener, but
    that became too complicated lisp for me. I was happy to manage this
    one.

    Now there is one little thing I need to get done: I have a waveform
    with complex values. This lead to my procedure writing
    complex( a, b )
    into my ascii file. I was hoping to be able to create a little lambda
    function that I could deliver into my procedure and have each point go
    through that lambda function before it was sent to the fprintf.

    I could probably also do some family math on the waveform before I send
    it to the dumper. I just feel too challenged at the moment to decide
    what is the better way as the number formatting also for reals does not
    look so nice, but at least gnuplot understand. (And I can do whatever
    needed to the function to make it fit my needs. The real power of
    open-source!!!)

    Here is the code. It is definitively not optimized nor effective as it
    is written by a skill novice.


    (procedure (sabDumpFamWaveform fileName waves @key (format "%g")
    (separator " "))
    (let (port xVec val paramName paramVal memberList)
    (unless (setq port (outfile fileName))
    (error "Could not write to file %s\n" fileName))
    ;-----------------------------------------------------------------
    ; Get the parameter name and values that builds the family
    ;-----------------------------------------------------------------
    (setq paramName (famGetSweepName waves))
    (setq paramVal (famGetSweepValues waves))
    ;-----------------------------------------------------------------
    ; Iterate over each parameter value and extract the corresponding
    ; waveform and put these in a list. Flattening the family.
    ;-----------------------------------------------------------------
    (fprintf port "%s" paramName)
    (fprintf port "%s" separator)
    (foreach val paramVal
    ;-----------------------------------------------------------------
    ; get the waveform for the particular parameter value. Put in list
    ;-----------------------------------------------------------------
    (setq memberList (tconc memberList (famValue waves val)))
    (setq xVec (drGetWaveformXVec (famValue waves val)))
    (fprintf port "%g" val)
    (fprintf port "%s" separator))
    (fprintf port "\n")
    (setq memberList (car memberList))
    ;-----------------------------------------------------------------
    ; iterate over the x-axis and print point from each member
    ;-----------------------------------------------------------------
    (for pos 0 (sub1 (drVectorLength xVec))
    (fprintf port format (drGetElem xVec pos))
    (foreach wave memberList
    (fprintf port "%s" separator)
    (fprintf port format (drGetElem (drGetWaveformYVec wave) pos)))
    (fprintf port "\n"))
    (close port)))
     
    Svenn Bjerkem, Sep 22, 2006
    #2
  3. It turned out not to be so difficult to solve but the solution is not
    as nice as I would like to. I could make two different family dumpers,
    one with a function reference and one without, but at the current stage
    I decide that I trade some time vs simpleness and have a function
    reference defined for any use of the dumper.

    A side effect of using a function object is that with a bit of
    programming inside that function, nice values can be returned to the
    printf function. So far I use format string %e, but an engineer like to
    have that %e in the e-3 e-6 e-9 etc. range. Since gnuplot take care of
    that for me I don't care very much right now.

    --
    Svenn


    ;==============================================================================
    ; sabDumpFamWaveform -- Dump a set of parametric waves (a family) to
    file as
    ; ascii.
    ;
    ; Author : Svenn Are Bjerkem
    ; Date : 2006-09-22
    ; Modified : 2006-09-25
    ; Limitations : Currently only one level can be flattened
    ;
    ; Example of usage:
    ; (setq fam (getData "M1:s"))
    ; (setq fun (lambda (x) (times 1.0 x)))
    ; (sabDumpFamEaveform "data.txt" fam fun ?format "%e" ?separator "\t")
    ;==============================================================================
    (procedure (sabDumpFamWaveform fileName waves fun
    @key (format "%g") (separator " "))
    (let (port xVec val paramName paramVal memberList)
    (unless (setq port (outfile fileName))
    (error "Could not write to file %s\n" fileName))
    ;-----------------------------------------------------------------
    ; Get the parameter name and values that builds the family
    ;-----------------------------------------------------------------
    (setq paramName (famGetSweepName waves))
    (setq paramVal (famGetSweepValues waves))
    ;-----------------------------------------------------------------
    ; Iterate over each parameter value and extract the corresponding
    ; waveform and put these in a list. Flattening the family.
    ;-----------------------------------------------------------------
    (fprintf port "%s" paramName)
    (fprintf port "%s" separator)
    (foreach val paramVal
    ;-----------------------------------------------------------------
    ; get the waveform for the particular parameter value. Put in list
    ;-----------------------------------------------------------------
    (setq memberList (tconc memberList (famValue waves val)))
    (setq xVec (drGetWaveformXVec (famValue waves val)))
    (fprintf port format val)
    (fprintf port "%s" separator))
    (fprintf port "\n")
    (setq memberList (car memberList))
    ;-----------------------------------------------------------------
    ; iterate over the x-axis and print point from each member
    ; through the function object provided on the calling line
    ;-----------------------------------------------------------------
    (for pos 0 (sub1 (drVectorLength xVec))
    (fprintf port format (drGetElem xVec pos))
    (foreach wave memberList
    (fprintf port "%s" separator)
    (fprintf port format
    (funcall fun (drGetElem (drGetWaveformYVec wave) pos))))
    (fprintf port "\n"))
    (close port)))
     
    Svenn Bjerkem, Sep 25, 2006
    #3
  4. Whilst you've answered your own question, I thought I'd post some existing code
    I have for dumping waveforms to text - to add to the solutions available.

    Andrew.
    /* abDumpWaveform.il

    Author A.D.Beckett
    Group Custom IC, Cadence Design Systems Ltd.
    Machine SUN
    Date Oct 23, 1997
    Modified Jan 31, 2005
    By A.D.Beckett

    Functions for dumping a waveform to a file

    Examples:

    abDumpWaveform(VT("/c") "data_c.out")
    abDumpWaveform(VT("/c") "data_c.out" "%e %e\n") ;; exponential format

    abDumpWaveformSplit() is equivalent to abDumpWaveform, but splits
    into files a little less than 2Gbytes (the split limit is an optional
    argument).

    ;; sampled output.
    ;; note that linRg and logRg generate a range of values,
    ;; with args from, to, step.
    abDumpSampledWaveform(VT("/c") linRg(0.01 0.05 0.005) "data_c.out")

    ;; multi-variable output
    ;; all waveforms must share same x-axis, as it doesn't do any interpolation (for
    ;; speed reasons). Interpolation could be done by collecting all the x-values, and
    ;; then using the value function.
    abDumpWaveforms("data.out" VT("/c") VT("/z") VT("/a"))
    abDumpWaveforms("data.out" VT("/c") VT("/z") VT("/a") ?format "%-10g" ?separator ",")

    ;; can also generate PSF now
    abDumpWaveformsToBinPSF("rawdir" VT("/c") VT("/z"))

    ;; can also write out multiple files if presented with a family
    abDumpFamily(VT("/c") "data.out")

    ***************************************************

    SCCS Info: @(#) abDumpWaveform.il 08/12/05.10:54:36 1.6

    */

    /*****************************************************************
    * *
    * (abDumpWaveform wave fileName @optional (format "%g %g\n")) *
    * *
    * Take a waveform object, write it out to the fileName specified *
    * with the format given. No sampling is done. *
    * *
    *****************************************************************/

    (procedure (abDumpWaveform wave fileName @optional (format "%g %g\n"))
    (let (port (xVec (drGetWaveformXVec wave))
    (yVec (drGetWaveformYVec wave)))
    (unless (setq port (outfile fileName))
    (error "Could not write to file %s\n" fileName))
    (for pos 0 (sub1 (drVectorLength xVec))
    (fprintf port format
    (drGetElem xVec pos)
    (drGetElem yVec pos))
    )
    (close port)
    ))

    /*****************************************************************
    * *
    * (abDumpWaveformSplit wave fileName @optional *
    * (format "%g %g\n") (split 2**31-512) ) *
    * *
    * Take a waveform object, write it out to the fileName specified *
    * with the format given. No sampling is done. Splits into *
    * multiple files when the number of bytes exceeds split *
    * *
    *****************************************************************/

    (procedure (abDumpWaveformSplit wave fileName @optional (format "%g %g\n") (split 2**31-512))
    (let (port (xVec (drGetWaveformXVec wave))
    (yVec (drGetWaveformYVec wave))
    str (len 0) (suffix 0))
    (unless (setq port (outfile fileName))
    (error "Could not write to file %s\n" fileName))
    (for pos 0 (sub1 (drVectorLength xVec))
    (sprintf str format
    (drGetElem xVec pos)
    (drGetElem yVec pos))
    (setq len (plus (strlen str) len))
    (when (greaterp len split)
    (close port)
    (postincrement suffix)
    (setq len (strlen str))
    (unless (setq port (outfile (sprintf nil "%s_%d" fileName suffix)))
    (error "Could not write to file %s_%d\n" fileName suffix))
    )
    (fprintf port "%s" str)
    )
    (close port)
    ))

    /********************************************************************
    * *
    * (abDumpFamily family fileNamePrefix @optional (format "%g %g\n")) *
    * *
    * Write out a sequence of files for a family. Could potentially do *
    * this automatically inside abDumpWaveform, but it's hard without *
    * using private functions. *
    * *
    ********************************************************************/

    (procedure (abDumpFamily family fileNamePrefix @optional (format "%g %g\n"))
    (let ((xVec (drGetWaveformXVec family))
    (yVec (drGetWaveformYVec family))
    index
    )
    (if (drIsWaveform family)
    ; then
    (abDumpWaveform family fileNamePrefix format)
    ;else
    (for pos 0 (sub1 (drVectorLength xVec))
    (setq index (drGetElem xVec pos))
    (unless (stringp index)
    (sprintf index "%L" index))
    (rexCompile "[^a-zA-Z0-9.]")
    (setq index (rexReplace index "_" 0))
    (abDumpWaveform
    (drGetElem yVec pos)
    (sprintf nil "%s_%s" fileNamePrefix index)
    format
    )
    )
    ) ; if
    ))

    /*********************************************************************************
    * *
    * (abDumpWaveforms fileName @key (format "%g") (separator " ") @rest waves) *
    * *
    * Write out a group of waveforms with a common x-axis to a file. It checks *
    * to see if the x-axis is the same, because otherwise some kind of interpolation *
    * would be necessary. An optional format string can be specified, so that *
    * the precision can be controlled. Also, an optional separator may be given. *
    * *
    *********************************************************************************/

    (procedure (abDumpWaveforms fileName @key (format "%g") (separator " ") @rest waves)
    (let (port xVec)
    (setq xVec (drGetWaveformXVec (car waves)))
    ;-----------------------------------------------------------------
    ; check to see if all waveforms have same X-axis
    ;-----------------------------------------------------------------
    (when (exists wave waves (neq xVec (drGetWaveformXVec wave)))
    (error "All waveforms must have same x-axis")
    )
    (unless (setq port (outfile fileName))
    (error "Could not write to file %s\n" fileName))
    (for pos 0 (sub1 (drVectorLength xVec))
    (fprintf port format
    (drGetElem xVec pos))
    (foreach wave waves
    (fprintf port "%s" separator)
    (fprintf port format (drGetElem (drGetWaveformYVec wave) pos))
    )
    (fprintf port "\n")
    )
    (close port)
    ))

    /**********************************************************************************
    * *
    * (abDumpSampledWaveform wave samplePoints fileName @optional (format "%g %g\n")) *
    * *
    * Dump the waveform at the sampled points passed in. wave is a waveform *
    * object, samplePoints is a list of x points to sample at, *
    * fileName is the file to write to, and format is an optional formatting string. *
    * *
    **********************************************************************************/

    (procedure (abDumpSampledWaveform wave samplePoints fileName @optional (format "%g %g\n"))
    (let (port)
    (unless (setq port (outfile fileName))
    (error "Could not write to file %s\n" fileName))
    (foreach point samplePoints
    (fprintf port format
    point
    (value wave point))
    )
    (close port)
    ))

    /*************************************************************************
    * *
    * Some global variables which enable simpler specification of the header *
    * part of the ASCII PSF file. *
    * *
    *************************************************************************/

    (setq abAsciiPSFTokenMap
    '((TOK_CR "\n")
    (TOK_PROP "PROP( ")
    (TOK_STRUCT "STRUCT( ")
    (TOK_OPEN "( ")
    (TOK_CLOSE ") ")
    (TOK_STAR "* ")
    )
    )

    (setq abAsciiPSFHeader
    '(
    HEADER TOK_CR
    "PSFversion" "1.00" TOK_CR
    TYPE TOK_CR
    "sweep" FLOAT DOUBLE TOK_PROP TOK_CR
    "key" "sweep" TOK_CR
    TOK_CLOSE TOK_CR
    "V" FLOAT DOUBLE TOK_PROP TOK_CR
    "units" "V" TOK_CR
    "key" "node" TOK_CR
    "tolerance" 1.00000e-06 TOK_CR
    TOK_CLOSE TOK_CR
    SWEEP TOK_CR
    "time" "sweep" TOK_PROP TOK_CR
    "sweep_direction" 0 TOK_CR
    "units" "s" TOK_CR
    "plot" 0 TOK_CR
    "grid" 1 TOK_CR
    TOK_CLOSE TOK_CR
    )
    )

    (setq abAsciiPSFLogFile
    '(
    HEADER TOK_CR
    "PSFversion" "1.00" TOK_CR
    "Log Generator" "drlLog rev. 1.0" TOK_CR
    "Log Time Stamp" "Thu Jan 3 16:23:59 2002" TOK_CR
    "simulator" "spectre" TOK_CR
    "version" "4.4.6.122001" TOK_CR
    "date" "4:23:59 PM, Thur Jan 3, 2002" TOK_CR
    "design" "myres.scs" TOK_CR
    TYPE TOK_CR
    "analysisInst" TOK_STRUCT TOK_CR
    "analysisType" STRING TOK_STAR TOK_CR
    "dataFile" STRING TOK_STAR TOK_CR
    "format" STRING TOK_STAR TOK_CR
    "parent" STRING TOK_STAR TOK_CR
    "sweepVariable" ARRAY TOK_OPEN TOK_STAR TOK_CLOSE STRING TOK_STAR TOK_CR
    "description" STRING TOK_STAR TOK_CR
    TOK_CLOSE TOK_CR
    VALUE TOK_CR
    "tran-tran" "analysisInst" TOK_OPEN TOK_CR
    "tran" TOK_CR
    "tran.tran" TOK_CR
    "PSF" TOK_CR
    "" TOK_CR
    TOK_OPEN "time" TOK_CLOSE TOK_CR
    "Transient Analysis `tran'" TOK_CR
    TOK_CLOSE TOK_CR
    END TOK_CR
    )
    )

    /***************************************************************
    * *
    * (abDumpPSFMagic port magic) *
    * *
    * A function for dumping the "magic" tokenised PSF header *
    * format information, to make writing the ASCII PSF simpler *
    * (believe it or not...) *
    * *
    ***************************************************************/

    (procedure (abDumpPSFMagic port magic)
    (let (mapped)
    ;-----------------------------------------------------------------
    ; Ensure that the PSF token map has been created
    ;-----------------------------------------------------------------
    (unless (boundp 'abPSFTokenMap)
    (setq abPSFTokenMap (makeTable 'PSFTokenMap nil))
    (foreach tokenMap abAsciiPSFTokenMap
    (setarray abPSFTokenMap (car tokenMap) (cadr tokenMap))
    )
    )
    ;-----------------------------------------------------------------
    ; Now write out each word in the magic list, mapping if necessary
    ;-----------------------------------------------------------------
    (foreach word magic
    (if (setq mapped (arrayref abPSFTokenMap word))
    (fprintf port mapped)
    (progn
    (print word port)
    (fprintf port " ")
    )
    )
    )
    )
    )

    /***************************************************************
    * *
    * (abDumpWaveformsToAsciiPSF fileName @rest waves) *
    * *
    * Create an ASCII PSF file containing the waves passed *
    * as remaining arguments. Note that all must have the same X *
    * axis *
    * *
    ***************************************************************/

    (procedure (abDumpWaveformsToAsciiPSF fileName @rest waves)
    (let (port xVec (waveNum 1))
    ;-----------------------------------------------------------------
    ; If a list of waves is passed in, use that instead
    ;-----------------------------------------------------------------
    (when (listp (car waves)) (setq waves (car waves)))
    ;-----------------------------------------------------------------
    ; Get the x vector of the first waveform
    ;-----------------------------------------------------------------
    (setq xVec (drGetWaveformXVec (car waves)))
    ;-----------------------------------------------------------------
    ; check to see if all waveforms have same X-axis
    ; much simpler this way...
    ;-----------------------------------------------------------------
    (when (exists wave waves (neq xVec (drGetWaveformXVec wave)))
    (error "All waveforms must have same x-axis")
    )
    (unless (setq port (outfile fileName))
    (error "Could not write to file %s\n" fileName))
    (abDumpPSFMagic port abAsciiPSFHeader)
    (abDumpPSFMagic port `(TRACE TOK_CR "group" GROUP ,(length waves) TOK_CR))
    ;-----------------------------------------------------------------
    ; Create a waveform name for each waveform
    ;-----------------------------------------------------------------
    (abDumpPSFMagic port
    (foreach mapcan wave waves
    ; next line is just to fool lint
    wave
    (list (sprintf nil "wave%d" (postincrement waveNum)) "V" 'TOK_CR)
    ))
    (abDumpPSFMagic port `(VALUE TOK_CR))
    ;-----------------------------------------------------------------
    ; Now write out the actual data
    ;-----------------------------------------------------------------
    (for pos 0 (sub1 (drVectorLength xVec))
    (fprintf port "\"time\" %.14e\n\"group\" " (drGetElem xVec pos))
    (foreach wave waves
    (fprintf port "%.14e\n" (drGetElem (drGetWaveformYVec wave) pos))
    )
    )
    (abDumpPSFMagic port `(END TOK_CR))
    (close port)
    )
    )

    /***************************************************************
    * *
    * (abDumpWaveformsToBinPSF rawdir @rest waves) *
    * *
    * Specify a raw directory, and a number of waveforms, this *
    * will create an ASCII PSF file and then use the psf *
    * utility to convert it to binary. *
    * *
    ***************************************************************/

    (procedure (abDumpWaveformsToBinPSF rawdir @rest waves)
    (let (port)
    (if (or (isDir rawdir) (createDir rawdir))
    (progn
    (apply 'abDumpWaveformsToAsciiPSF (cons (strcat rawdir "/tran.asc") waves))
    (setq port (outfile (strcat rawdir "/logFile")))
    (when port
    (abDumpPSFMagic port abAsciiPSFLogFile)
    (close port))
    ;------------------------------------------------------------
    ; Use the transpose option (-x) (think this is right...)
    ;------------------------------------------------------------
    (system
    (sprintf nil "psf -x -i %s/tran.asc -o %s/tran.tran"
    rawdir rawdir)
    )
    t
    )
    (error "Could not create directory %s" rawdir)
    )
    )
    )
     
    Andrew Beckett, Oct 9, 2006
    #4
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.