Главная > Tools > Скрипт для преобразования списка компонентов в удобоваримый вид

Скрипт для преобразования списка компонентов в удобоваримый вид

Как многие знают, я использую DipTrace и нежно его люблю. Разумеется, как всякая уважающая себя EDA-система, DipTrace умеет создавать файл списка используемых компонентов. Однако в таком файле DipTrace (да и P-CAD тоже) просто перечисляет каждый компонент с указанием его позиционного обозначения (RefDes), типа (почему-то в DT это поле названо Name) и номинала (Value).

Очевидно, гораздо удобнее было бы иметь список компонентов, сгруппированный по принципу «тип : номинал : количество/перечень элементов этого номинала» (или как-то так). Скрипт на Lua, который я вчера написал, занимается ровно тем, что преобразует выдаваемый DipTrace перечень компонентов к подобному виду.

Пример работы скрипта.

DipTrace выдает что-то такое (вообще, вывод там настраивается; я настроил так):

RefDes	Name		Value
C1	CAP_0805	0.1
C2	CAP_0805	0.1
C3	CAP_0805	0.1
C4	CAP_0805	0.1
C5	CAP_0805	0.1
DA1	VREG		L78L33
DD1	MCU_TQFP	ATMEGA48
J1	CONN10F	
J2	CONN10F	
J3	CONN10F	
J4	CONN10F	
J5	CONN10F	
Q1	MOSFET		IRLML5203
Q2	BJT		BC817
Q3	BJT		BC817
Q4	BJT		BC807
Q5	MOSFET		IRLML5203
Q6	MOSFET		IRLML2803
R1	RES_0805	1M
R2	RES_0805	0R
R3	RES_0805	1K0
R4	RES_0805	510R
R5	RES_0805	10R
R6	RES_0805	100R
R7	RES_0805	10R

Мой скрипт приводит это в такой вид:

MCU_TQFP:	 	 
DD1		ATMEGA48	1
MOSFET:	 	 
Q6		IRLML2803	1
Q1,Q5		IRLML5203	2
CAP_0805:	 	 
C1,C2,C3,C4,C5	0.1		5
RES_0805:	 	 
R4		510R		1
R1		1M		1
R3		1K0		1
R6		100R		1
R5,R7		10R		2
R2		0R		1
BJT:	 	 
Q4		BC807		1
Q2,Q3		BC817		2
CONN10F:	 	 
J1,J2,J3,J4,J5	[No Value]	5
VREG:	 	 
DA1		L78L33		1

На вход скрипт принимает CSV-файл перечня элементов из DipTrace. Разумеется, при экспорте надо выбрать приведенные выше поля. На выходе тоже получается CSV-файл.

Быстрый рецепт использования для нетерпеливых: создаем текстовый документ с содержимым, приведенным ниже (копипастим) и сохраняем его как скрипт на Lua; из DipTrace экспортируем в ту же папку перечень компонентов: файл называем bom.csv, разделители — запятые. Запускаем скрипт, на выходе получаем bom_summary.csv в том формате, что показан выше.

Разумеется, чтобы все радовало глаз, у компонентов должны быть корректно прописаны интересующие нас поля, а в системе должен стоять интерпретатор Lua.

Сам скрипт:

 
-- This script structurizes bill of materials.
-- Accepts data from DipTrace (in CSV format).
-- Produces new CSV file with structured data.

BOM_FILENAME = "bom"; -- w/o extension

bom = io.open(BOM_FILENAME .. ".csv","r");

line = bom:read("*l"); -- Skipping header
line = bom:read("*l");

records = {}; -- Table to read file entries to

while line ~= nil do
-- Until the end of file

	-- Parsing required info

	RefDes	= string.match(line,"\"(.+)\";.+;.+");
	Name	= string.match(line,".+;\"(.+)\";.+");
	Value	= string.match(line,".+;.+;\"(.+)\"");

	-- Fixing possibly missing values

	if Name == nil then

		Name = "[No Name]";

	end;

	if Value == nil then

		Value = "[No Value]";

	end;

	if RefDes == nil then

		RefDes = "[No RefDes]";

	end;

	if records[Name] ~= nil then
	-- If there's already a component group for this type name present

		if records[Name][Value] ~= nil then
		-- If there's already a component group for this type name and value present

			-- Add current component to this existing group
			records[Name][Value]["Parts"] = records[Name][Value]["Parts"] .. "," .. RefDes;
			records[Name][Value]["Count"] = records[Name][Value]["Count"] + 1;

		else
		-- If the current component is of one of already present type name groups, but of
		-- new value

			-- Create new value group in existing type name group
			-- and add current component to it
			records[Name][Value] = {};
			records[Name][Value]["Parts"] = RefDes;
			records[Name][Value]["Count"] = 1;

		end;

	else
	-- If this is a component of new type name group

		-- Create a new component type name group with new value group in it
		-- and add current component to it
		records[Name] = {};
		records[Name][Value] = {};
		records[Name][Value]["Parts"] = RefDes;
		records[Name][Value]["Count"] = 1;

	end;

	-- Move to next component record

	line = bom:read("*l");

end;

bom:close();

-- Now we have a structurized data and can retreive it in any desired way

summary = io.open(BOM_FILENAME .. "_summary.csv","w");

-- Group data by component type name and value

for Name in pairs(records) do

	print("Components of type ",Name,":");

	summary:write(Name,":; ; \n");

	for Value in pairs(records[Name]) do

		print(records[Name][Value]["Parts"]," : ",Value,";",records[Name][Value]["Count"]," element(s).");
		summary:write(records[Name][Value]["Parts"],";",Value,";",records[Name][Value]["Count"],"\n");

	end;

end;

-- Happy end

summary:close();

А теперь для достаточно любознательных, но слишком ленивых для того, чтобы читать комментарии в скрипте и сопоставлять их с кодом, немного о том, как оно работает.

Сила луны Lua, как известно, состоит в таблицах, и здесь я использую именно их мощь. Таблица в Lua, в общем, представляет собой ассоциативный массив, индексами и элементами которого могут быть абсолютно любые значения, что предоставляет потрясающие возможности для задач поиска, упорядочивания, структуризации и тому подобных. Здесь я создал таблицу таблиц таблиц под названием records, элементами которых являются строки и числовые значения.

  • records[Name] — по таблице на каждый тип компонентов;
  • records[Name][Value] — в каждом типе компонентов по таблице для каждого номинала;
  • records[Name][Value][«Parts»] — каждому номиналу каждого типа компонентов соответствует строка, в которой перечислены позиционные обозначения компонентов, к нему относящихся;
  • records[Name][Value][«Count»] — каждому номиналу каждого типа компонентов соответствует переменная с количеством элементов такого типа и номинала.

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

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

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

Имя файла со списком элементов вынесено в переменную, находящуюся в самом верху, можно поменять по вкусу (расширение .csv вписывать не надо). Выходной файл всегда называется <имя_входного>_summary.csv.

По идее, этот скрипт можно использовать и c другими EDA-системами, только надо иметь в виду, что DipTrace выдает значения в CSV-файл как

"<значение>";"<значение>";"<значение>"
"<значение>";"<значение>";"<значение>"
...

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

Рубрики:Tools
  1. серега
    02/02/2014 в 18:27

    нестандарный выбор, всеже почему не питон ?

    • YS
      02/02/2014 в 18:49

      Все очень просто — я не знаю питона и не горю желанием его изучать.🙂

      А Lua я использую в работе над своим исследованием на кафедре (весь софт для расчетов пишется на ней), так что интерпретатор у меня уже стоит.

      В целом, сравнение Lua и Python можно посмотреть тут. Для меня наиболее важно, что:

      — Lua компактнее;
      — Lua быстрее;
      — Lua не принуждает к определенному стилю написания кода, например, к ООП;
      — У Lua красивый, простой и минималистичный синтаксис, слегка напоминающий смесь Pascal и Javascript.

  1. No trackbacks yet.

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s