summaryrefslogtreecommitdiff
path: root/Windows/spice/share/ngspice/scripts/spectrum
blob: 3e394432779fabdb32aa39ced8e63d7f5717e989 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
* Fourier Series Function for SPICE
* This script is offered here for learning purposes, even if it is outdated
* and superseeded by the spec function and especially by the much faster fft function.
* You may use this script in conjunction with e.g. a ringoscillator output (see
* the ngspice manual, chapter 17).

.control
  begin

* Variable argc delivers the number of command line parameters given by the user 
* after the 'spectrum' command  
   if ($argc lt 4)
 	 echo   Error: Too few arguments.
	 echo   '      'Spectrum produces a plot containing a fourier series transformation of 
	 echo   '      'the specified vectors
	 echo   usage: spectrum startfreq stop step vec [[vec] ...]
	 goto bottom
   end

* Check if vectors 'time' and any input vector(s) are available
* argv[n] delivers the command line entries after the 'spectrum' command,
* starting with argv[1]. $argv[4-len] delivers the value of all tokens, 
* starting with postion 4 till the end of the command line    
   if ( time eq time ) 
      foreach vec $argv[4-len]
         if ( $vec eq $vec )
	     else
            goto bottom
	     end
      end
   else
      echo '       'Spectrum can not work without a time vector from a transient analysis.
      goto bottom
   end

   * generate a new plot entitled 'scratch', which will hold intermediate
   * results and will be discarded after their evaluation.   
   set dt=$curplot
   set title=$curplottitle
   set curplot=new
   set scratch=$curplot

   * A vector 'span' is created in the 'scratch' plot to hold the time difference
   * of the transient simulation. {$dt}.time allows to access the 'time' vector
   * from the dt plot (which is normally named 'tranx' with x a consecutoive
   * integer number, depending on the amount of transient simulations already run
   * in the present job.   
   let span={$dt}.time[length({$dt}.time)-1]-{$dt}.time[0]

* Calculate the number of steps in all of the spectra to be evaluated below
   if ($argv[3] gt 0.999/span)
       let fpoints= ( $argv[2] - $argv[1] ) / $argv[3] +1
	   if (fpoints < 2)
	       echo frequency start stop or step not correctly specified
		   goto reset
	   end
   else
       echo   Error: time span is not long enough for a step frequency of $argv[3] Hz
	   goto reset
   end
   let lent = length({$dt}.time)
   set lent = "$&lent"
   let nyquist = {$lent}/2/span
   if ($argv[2] gt nyquist)
       echo   Error: The nyquist limit is exceeded, try a frequency less than "$&nyquist" Hz
	   goto reset
   end
   set fpoints="$&fpoints"

   * generate a new plot to hold the spectra   
   set curplot=new
   set spec=$curplot
   set curplottitle=$title
   set curplotname='Spectrum Analysis'
   
* argv[3] is the third agrgument from the input line 
* spectrum 1 1000MEG 10MEG v(out25) 
* that is the delta frequency
* The fcn vector(n) creates a vector of length n, its elements have
* the values 0, 1, 2, 3, ..., n-2, n-1. Each element then is multiplied 
* with the frequency step value. 
   let frequency=vector( $fpoints )*$argv[3]

* Add an frequency offset to each element of vector 'frequency'
* to suppress the (typically) large dc component.
   dowhile frequency[1] < ( $argv[1] + 1e-9 )
       let frequency = frequency + $argv[3]
   end

* For each input vector given on the command line,
* create a new vector for complex numbers   
   foreach vec $argv[4-len]
       let $vec = vector( $fpoints ) + j(vector( $fpoints ))
	   reshape $vec [{$fpoints}]
   end

* $scratch is a plot for intermediate results, will be destroyed during cleanup
* $dt is the plot with the original data
* $spec is a plot for storing the spectrum   
   set curplot=$scratch

   * some test   
   let npers=1
   let test = span-2/$argv[3] + 1e-9
   while test > 0
       let npers = npers + 1
       let test = test-1/$argv[3]
   end

   * Do the spectrum calculations  
   let ircle = 2*pi*max(-1,({$dt}.time-{$dt}.time[{$lent}-1])*{$argv[3]}/npers)
   let win = 1 - cos(ircle)
   let ircle = npers*ircle
   let circle = ircle * ({$spec}.frequency[0]/$argv[3] - 1)
   let k=vector( $fpoints ) 
   foreach k $&k
      let circle = circle + ircle 
      foreach vec $argv[4-len]
	      let tmp = win*{$dt}.{$vec}
          let {$spec}.{$vec}[{$k}] = 2*(mean(cos(circle)*tmp),mean(sin(circle)*tmp))
      end
   end

* plot (and write) the generated spectrum   
   set curplot = $spec
   settype frequency frequency
   foreach vec $argv[4-len]
      let spectrum = mag({$vec})
      plot spectrum
      write specout.out spectrum
   end
   
* If you have an oscillator, fimd its frequency 
* as maximum of vector spectrum or goto end (uncomment next line)
*  goto cleanup
   set curplot=$scratch  
   let counter = 0
   let contents = 0
   let freqmax = 0
   let spectrum = {$spec}.spectrum
 
   foreach spectrum $&spectrum
       if counter > 4
         if ( contents < $spectrum )
            let contents = $spectrum
			set count = "$&counter"
			let freqmax = {$spec}.frequency[{$count}]
         end
      end
	  let counter = counter + 1
   end
   
   echo   
   echo Osc. frequency at "$&freqmax" Hz   
   echo
   goto cleanup
   
   label reset
   set curplot=$dt   
   label cleanup
   destroy $scratch
   unset fpoints dt scratch spec vec k title lent
   label bottom

 end