1
31 Oct 2016 01:19:22

Ngspice tips

Ngspice - это симулятор электронных схем, при знакомстве с ним многое не понятно и приходится много читать документацию. Я опишу здесь некоторые важные для меня вещи которые позволили решить ряд практических задач. А именно фичи, которые доступны но невидны пользователю первое время.

Пара слов про помощь и мануал

Если что-то неполучается и нужна подробная информация то набирается из интерпитатора > help и читаете.
Также можно почитать pdf, там собрана наиболее полная информация http://ngspice.sourceforge.net/docs/ngspice-manual.pdf

Кратко о задачах которые надо было решить

Получение на одном графике данных, например с шимом у которого меняется скважность в определенные моменты времени.
Автоматизация процесса. Навыки работы с векторами и понимание базовых принципов и концепций интерфеса ngspice.

Как ведет себя ngspice при симуляции схем, где он хранит данные, как ими пользоваться?

Ваш netlist лежит например в файле, вы его считали и запустили например анализ переходного процесса
tran 5ns 600u
После этой комманды ngspice расчитает напряжение в узлах, токи в ветвях и построит несколько векторов (массивы с данными) которые будут хранить данные функции этих параметров от времени. Чтобы посмотреть какие векторы доступны для графика вы можете использовать display.

ngspice 596 -> display
Here are the vectors currently active:
Title: batch
Name: tran3 (Transient Analysis)
Date: Sat Oct 29 17:40:35  2016
    end_time            : time, real, 1 long
    index               : notype, real, 1 long
    time                : time, real, 600007 long [default scale]
    v1#branch           : current, real, 600007 long
    vcc                 : voltage, real, 600007 long
    vout                : voltage, real, 600007 long
ngspice 597 -> 

 

Тут вы видите все векторы доступные для вывода на график, их длина в данном случае 600007, это значит что на каждый элемент вектора time, т.е. на каждый момент времени в векторах vcc\vout\v1#branch есть соответсвующее значение по напряжению, току и тд. Иными словами команда симуляции которую вы запускаете создает контекст (называется plot) в котором хранит все векторы конкретной симуляции.

Чтобы посмотреть график вы пишите

ngspice 597 -> plot vcc

ngspice 598 ->

И вам открывается график напряжения в узле vcc по времени.

Вы можете изменить время на что-либо другое, например посмотреть график тока от напряжения в каком-то узле

setscale vcc
Эта команда выбирает вектор по которому строится график (шкала x)

 

Когда пишите plot v1#branch, то ток (шкала y) будет показан в зависимости от напряжения в узеле vcc.
Чтобы вернуть все назад и использовать время напишите: setscale time

Так вот, контекст в котором хранятся все векторы конкретной симуляции называется plot, вы можете посмотреть все существующие контексты

 ngspice 602 -> echo $plots
const unknown1 tran1 tran2 tran3 tran4 tran5 tran6 tran7 tran8 tran9 tran10
ngspice 603 -> 
Или так
ngspice 603 -> setplot
    Type the name of the desired plot:
    new    New plot
    tran10    batch (Transient Analysis)
    tran9    batch (Transient Analysis)
    tran8    batch (Transient Analysis)
    tran7    batch (Transient Analysis)
    tran6    batch (Transient Analysis)
    tran5    batch (Transient Analysis)
    tran4    batch (Transient Analysis)
Current tran3    batch (Transient Analysis)
    tran2    batch (Transient Analysis)
    tran1    batch (Transient Analysis)
    unknown1    data (intermidiate variables)
    const    Constant values (constants)
? 
Между ними можно переключаться и просматривать графики разных анализов, и даже можно совмещать разные графики из разных анализов в одном!

Чтобы переключиться в какой-либо plot:

ngspice 604 -> setplot tran7

ngspice 605 -> display

Новый плот создается каждый раз когда вы пишите какую нибудь команду анализа op tran dc ac и т.д.
У ngspice есть ряд ограничений, эти ограничения не позволяют менять на ходу характеристики источника напряжения и строить динамический график (например менять шиму длину испульса). Но сам ngspice все же позволяет это сделать. Когда в интерпретаторе вы пишите разные команды - программа выполняет запрошенные действия. Также можно в каком-либо файле или в самом netlist'е прописать

.control
.endc

 

И каждый раз кода файл будет исполняться вы можете указать там все нужные команды и они будут вызваны автоматически, чтобы каждый раз не писать все это дело в интерпретаторе. Например если у вас есть netlist и вы хотите выводить сразу же график напряжения на резисторе как функцию от времени, то пишите там нужную ноду, например

.control
tran 5ns 100ns
plot vcc
.endc
Программа сделает анализ и тут же выведет график.

И теперь сообственно самое главное - зачем писалась эта статья - чтобы поделиться способом динамически менять характеристики источника напряжения (или любого другого устройства) и анализировать все это, а затем показывать как непрерывный единственный график целостно.

Для этого нам надо будет прогонять несколько раз анализы (tran) после каждого прогона записывать последнее напряжение которое было при переходном процессе, затем менять характеристики источника, ставить начальные условия (последнии наряжения с предыдущего состояния) и запускать анализ и сдвигать его на временной интервал чтобы как-бы продолжить с той точки времени где предыдущий график был оборван чтобы получить непрерывный анализ с меняющимися во времени параметрами.

Теперь по порядку - начальные условия - например напряжения на узлах задаются командой IC (initial conditions),
например

.ic v(vout) = 2.91471
Задать узлу vout начальное напряжение 2.9.
когда пишите команду анализа например переходного процесса указываете uic - use initial conditions
tran 5ns 100ns uic
С этим понятно, затем поскольку ngspice предоставляет инструменты скриптования то мы можем записывать значения из векторов в переменные или в новые вектора и использовать их в будущих анализах.

Есть ряд способов менять параметры устройств например alter, altermod .param и т.д. но у каждого из них есть свои ограничения и их нужно использовать с умом, проще всего генерировать файл с нужными значениями и запускать его заного, затем получать значения последних напряжений и обрабатывать вектора.

Для этого есть команды foreach, source, include, echo
foreach - просто цикл.
source - выполнить внешний файл (считать нетлист и запустить все скрипты внутри)
include - просто вставить содержимое другого файла в текущий
echo - позволяет нам записывать переменные, данные векторов из ngspice в файл в любом нужном нам формате.

Пример файл iteration.cir

Iteration

.include "tmp.cir"

v1 vcc 0 pulse(0 3.3 0ns 2ns 2ns {pw} 60ns)
r1 vcc vout 100
c2 vout 0 100n
* l1 1 vout 10m

.end

Есть такой нетлист, {pw} - это подстановка параметра (переменной), которая объявляется в файле .include "tmp.cir" , также там задаются IC (initial conditions) для наших узлов.

То есть у нас получается что скважность шима зависит от переменной pw (pulse width), а начальное напряжение от директивы IC в файле tmp.cir, содержимое этого файла:

.param pw=55.5ns
.param cdc=55.5
.ic v(vout) = 2.91471
.param icv = 2.91471

 

Затем у нас есть другой файл, назовем его для примера batch:

foreach i 5 10 15
    echo "-------------interation----------------"
    * Prepare VCC pwm parameters for each analyse segment.
    echo ".param pw={$i}ns" > tmp.cir
    echo ".param cdc=$i" >> tmp.cir
    echo ".ic v(vout) = $&last_v" >> tmp.cir
    source iteration.cir
end

 

Смысл в том что foreach перебирает литералы 5 10 15 и на каждой итерации записывает их в переменную $i, затем она пишет в файл tmp.cir с помощью echo,
> полностью перетирает содержимое файла, в то время как >> доклеивает к концу, т.е. вначале итерации мы очищаем предыдущее содержимое файла tmp.cir и записываем туда param, после ic добавляется pw, затем мы исполняем наш файл iteration.cir с помощью source, а interation.cir подключает к себе через include tmp.cir, таким образом у него меняются данные. В самом iteration.cir или в batch.cir мы затем сможем написать команду анализа например tran 5ns 100ns uic, что на каждую итерацию создаст отдельный плот в каждом из которых будет находится свой набор векторов отвечающих конткретным анализам с конкретными разными условиями (скважность шима например).

Теперь остается последнее! Нам надо объединить эти данные в один график! Команда tran всегда использует время 0 в качестве начальной точки, если вы укажете в tran start stop times то анализ все равно начнется со времени в точке 0, но будет записан только ограниченный вами интервал (тоесть первая часть потеряется). Для решения этой проблемы нам не надо указывать старт time а всегда считать с 0, затем мы к вектору time этого plot'а просто добавим нужный офсет и график сдвинется по времени без потери данных! Например

setplot tran2
time += 10ns
time - это вектор, математические операции меняют каждый элемент вектора, тоесть ко всем его значениям будет прибавлено 10 наносекунд.

Отлично! Теперь мы имеем два plota с двумя графиками, к примеру один от 0 до 100ns, а второй от 100ns до 200ns, как показать это на одном графике?! Очень просто
Команда plot позволяет обращаться к разным plot'ам и выводить их все одновременно на одном и том же графике

 

пример, посмотрим какие плоты есть
ngspice 603 -> setplot
Type the name of the desired plot: new New plot tran10 batch (Transient Analysis) tran9 batch (Transient Analysis) tran8 batch (Transient Analysis) tran7 batch (Transient Analysis)
 
и выведем два вектора двух разных plot'ов на одном графике
plot tran9.vcc tran8.vcc
Готово! Получается что если график сдвинут по времени то он отобразится в нужном месте на одном графике с функцией из совершенно другого plot'a.

Пару способов делать это с помощью скрипта и пара заметок
переменные это просто строки, в них нельзя использовать выражения (expressions), а в векторах можно, например set x = 3 + 1, получим строку 3+1, а если используем let x = 3 + 1; получим 4.
Также с echo & print, echo выводит строки, а print выражения. в контексте set и echo все же есть набор подстановочных возможностей, если будете писать имя переменой с $name, то оно подставится на значение (ака токен), а если хотите обратиться к вектору то $&name[0]
поменять текущий плот: setplot $some_name
сохранить текущий плот в переменную: set some_name = $curplot; echo $some_name // your current plot
получить последнее значение вектора: let my_last_voltage = {$some_name}.vcc[length({$some_name}.vcc) - 1]; pint my_last_voltage
создать вектор с нарезанными значениями через определенный шаг: compose pwm_pws start = 15 stop = 60 lin = 10; print pwm_pws

Ну и напоследок приведу пример и картинку своего скрипта который расчитывал разные шим сигналы. Эмулировал работу переключения шима микроконтроллером. Прошу прощения за сумбурность изложения, но я хотел поделится решением, так как довольно долго его искал и счёл что это может кому-либо пригодится, но я торопился чтобы изложить побольше и побыстрее в связи с нехваткой времени. Здесь рабочая программа и ее график

 

Batch
.control
set curplot = new
compose pwm_pws start = 15 stop = 60 lin = 10
print pwm_pws
let dtime = 500u
set astep = 1ns
set data = $curplot
set curplottitle = data
set curplotname = "intermidiate variables"
set prev_plot = ""
set plot_cmd = ""
let last_v = 0
let index = 0
foreach i $&pwm_pws
    echo "-------------interation----------------"
    * Prepare VCC pwm parameters for each analyse segment.
    echo ".param pw={$i}ns" > tmp.cir
    echo ".param cdc=$i" >> tmp.cir
    set curplot = $data
    * Use last Vout value from previous simulation to continue analyse.
    echo "MY VAL INDEX IS $&index"
    if index
        echo "DEBUG index is true"
        echo "DEBUG: last_v = $&last_v"
        if last_v
             echo ".ic v(vout) = $&last_v" >> tmp.cir
        end
    end
    echo ".param icv = $&last_v" >> tmp.cir
    * Update netlist with current iteration context.
    source iteration.cir
    tran $astep $&dtime
    echo "vout of current plot **************** IS"
    print vout[0]
    echo $curplot
    set prev_plot = $curplot
    set plot_cmd = "$plot_cmd {$prev_plot}.vout {$prev_plot}.vcc"
    echo $plot_cmd
    let index = {$data}.index
    if not index
        set curplot = $data
        let time = {$prev_plot}.time
    else
        let end_time = time[length(time) - 1]
        let time = {$data}.time
        * Avoid rounding error that leads to discrete graph.
        let time[length(time) - 1] = end_time + $dtime
        set curplot = $data
    end
    * Store analyse vector to our data plot context.
    * let {$prev_plot}_vout = {$prev_plot}.vout
    let last_v = {$prev_plot}.vout[length({$prev_plot}.vout) - 1]
    let time = time + dtime
    let vout[length(time) - 1] = vout[length(vout) - 1]
    let index = index + 1
    echo "index is $&index"
end
plot $plot_cmd
.endc
.end

 


 

 

На графике радугой это шим сигнал с разной частотой, шим подается на RC фильтр, после фильтра напряжение показано на графике ступенями. В графике есть немного разрывов, это связано с моими недавними правками скрипта и парой ошибок, но основное внимание в статье было уделено идеи, чтобы поделиться с вами и подсказать сопособ как анализировать схемы в более сложном ключе!

Спасибо за внимание

Comments:

аноним
Говорят, из-за границы домой попав, после долгих во́льтов, Маяковский дома поймал “Клопа” и отнёс в театр Мейерхольда.
14 дек 2016 в 14:23

add comment