惯性算法在数字电路逻辑建模实例中的实现

1.简介


我们将继续讨论嵌套自动机这一主题的第二部分。在第一,我们研究递归算法,其中,有嵌套自动机的模型,连接面向对象能力,它原来是不那么难以实现。但是嵌套自动机的可能性不限于此。因此,在描述自动机程序的控制模型时,确定了惯性算法,这也是基于嵌入自动机的思想。惯性算法很难在计算模型的普通框图的框架中进行想象,该框图不提供控制返回到子例程调用之前的位置。但是我必须说,传统的自动机还可以取消“即时”过渡。然而,对于自动机,这不仅可以想象得到,而且可以实现。

数字电路的惯性算法和逻辑建模相关主题。并不是因为惯性延迟使所考虑的算法类别具有名称,而是因为惯性延迟的延迟动作的含义有多大,这才转移到了它们的工作意义上。当然,这不是名字。在UML中,使用历史状态的概念可以实现类似的算法。尽管通常没有必要使用UML对数字电路进行建模,但这种类比很简单。只是回到起点的情况,如果有某些事情迫使人们这样做,那似乎是最自然的。例如,拒绝购买机票,取消银行业务/交易,断开网络连接等。等等最后,如UML中所述,如果不使用历史状态,则此类算法的实现不会那么“美丽” [1]。

数字电路的逻辑建模本身就是广泛而有趣的话题。重新阅读并不会伤害她。正如我们将看到的,自动编程技术可以提供一种更好的方式来描述,实现和逻辑建模数字电路。追求主要目标,我们将一无所知-考虑一种有趣的,有用的,最后只是一类漂亮的算法,它对于自动机是很自然的,但是在其他计算模型中却很难实现。

2.数字电路的逻辑建模


文献通常考虑两种对数字电路建模的方法-编译和事件。编译的能力有限,因为不考虑元素延迟,需要对元素进行排名和中断反馈[2]。事件方法没有这种限制,它基于与电路内信号值变化相关的跟踪事件。我们将不考虑编译,而是将重点放在将事件与在自动编程的可能性范围内实现的方法进行比较,因此,我们将以自动方式进一步对其进行调用。

例如,以图[2]中的电路为例。图1显示了她的作品来源图。2.考虑了两种选择:当电路的逻辑元件具有相同的延迟时具有单个延迟,而当元素B和E的延迟是其余电路元件的两倍时,则具有分布式延迟。
图片

图。1.电路示例。

图片

图。 2.建模实例:a-单个延迟; b-分布式延迟。

使用自动模拟方法,您甚至不必发明任何东西,因为无需创建足够具体的语言来描述实现电路关系的电路和结构,也不需要足够具体的算法来检测电路建模过程中的事件,然后将其用作构造电路图的基础(有关两者的描述,请参见[2] )

在自动机的情况下,将创建用于程序设计的自动机技术常用的逻辑元素模型,这些模型包含在逻辑元素库(BLE)中。此外,在此库的基础上,创建了一组与电路元件数量相对应的并行自动机过程,使用逻辑元件模型的输入/输出通道指示了连接之间的连接(为此,在VKPA环境中,本地过程变量通常就足够了)。总之,电路模型由输入信号的过程生成器和显示信号图的过程补充。

在VKPa环境中的示例的仿真结果如图2所示。图3与图3的图完全一致。 2.是的,不可能立即实现这种巧合。并不是因为模型存在问题,而是因为实际上“科学选择方法”必须计算输入信号的持续时间,事实证明,这具有重大影响。但是在[2]中,没有关于此的一句话,也没有提及输入信号的参数。通过发现1)持续时间等于延迟的三倍,以及2)相对于信号(a)的信号偏移(b)应等于单位延迟来达成完全一致。要解释此问题,请参见图。图4显示了输入信号不同持续时间的信号图(并且这没有考虑其位移)。

图片

图。3.在VKPa中的仿真结果:a-单个延迟;b-分布式延迟。

图片

图。4.不同输入信号持续时间的仿真结果

考虑来自同一源的另一个电路示例[2]。其工作方案和时序图如图2所示。5.在事件方法的框架中,要“计算”时间图,需要20个仿真步骤(更多详细信息,请参见[2])。但是,如此处所述,如果选择了惯性类型的延迟,则需要更复杂的算法,并因此需要更多的步数。在我们的情况下(使用自动建模方法的情况),使用先前的模型,我们需要用鼠标“单击20次”转到图10中的图。5,去除原电路不必要的元件。在VKPa中获得的电路仿真结果如图2所示。6。

图片

图。5.电路示例及其时序图。

另外,图中的图。在图5中,我们在元素OR元素I处添加了平行线。图6显示了单个延迟情况下的操作。如果设置较大的延迟并设置惯性类型的延迟,则图d将变为一条直线。因此,惯性延迟大于单个值的And元素将不会错过通过这些输入信号a和b的组合在其输入处生成的脉冲。请注意,仅对延迟大于一的元素使用延迟类型才有意义。

图片

图。6.对图中的电路建模。5和元素And(d)。

3.逻辑元素的实现


在一般情况下,任何逻辑元素都可以表示为两个块的串联连接(参见图7)-一个没有延迟的理想逻辑元素和一个块,可以将其视为传播延迟(传输延迟)或惯性延迟[2]。

图片

图。7.延迟逻辑元件模型。

理想的逻辑元素很容易通过常规逻辑功能实现,并且延迟块模型可以以自动机模型的形式表示-自动机模型是包含运输和惯性延迟的通用模型。这种通用延迟的模型如图2所示。图8中显示了嵌套自动机的模型。9.清单1显示了它们在C ++中的实现以及作为自动化编程技术的一部分。

图片

图。8.通用延迟模型。

图片

图。 9.用于通用延迟的嵌套自动机模型。

图中的机器8和图。 9支是混合的Mili-Moore突击步枪。图中主要自动机的操作8.首先在操作y12中创建局部变量并初始化引用(谓词x12检查所有这一切)。谓词x3正确运行需要中间状态“ ss”,该谓词具有到输入变量的链接,该输入变量可能未初始化。从“ ss”状态开始,模型进入与延迟输出相对应的状态,同时导致嵌套自动机。注意,只有在嵌套自动机的操作完成后,才会启动自动机状态下的动作(摩尔自动机的动作)。它们最终将设置当前延迟值和输出变量的状态。

如果定义了延迟值,则动作y13会根据延迟的类型创建必要的嵌套自动机。嵌入式传输延迟自动机仅对离散时间时钟周期的设置值进行计数(延迟的持续时间由离散时钟周期的数量确定),而惯性延迟还控制输入信号的电平。在这种情况下,我们注意到谓词x3的返回值取决于顶级自动机的当前状态。

图中自动机的实现 8、9反映了清单3。考虑代码,您应该注意虚拟方法f(),该方法一方面实现一个或另一个重叠的抽象逻辑函数,另一方面执行(如果指定)反转。所有这些对于实现逻辑元素的派生模型都是必需的。清单2演示了这种NAND门的实现。

清单1.实现通用延迟逻辑元素
#include "lfsaappl.h"

extern LArc TBL_DiscreteTime[];
class FDiscreteTime :											
	public LFsaAppl											
{													
public:													
    enum {cvarINE, cvarExlusiveOR, cvarOrNot};
    void MooreAction();
	bool	FCreationOfLinksForVariables();								
    LFsaAppl* Create(CVarFSA *pCVF) { Q_UNUSED(pCVF) return new FDiscreteTime(nameFsa); }
	bool FInit();											
    FDiscreteTime(string strNam, LArc* pTBL = TBL_DiscreteTime);
	~FDiscreteTime(void);										
	CVar *pVarType;		// delay type 0-transport; 1- inertial
	CVar *pVarX1;		// input variable
	CVar *pVarStrNameX1;	// input variable name
    	CVar *pVarIfNotX1;	// inverse of the first input variable
    	CVar *pVarY1;		// output variable
	CVar *pVarStrNameY1;	// output variable name
	CVar *pVarValue01;	// delay value from 0 to 1
	CVar *pVarValue10;	// delay value from 1 to 0
    	CVar *pVarNegationY;// output inversion 0 - no inversion; 1- inversion
    	virtual int x3();	// input analysis
	virtual int x12();	// link setup analysis
    	virtual bool f();
    	int nTypeElement;
protected:
// predicates												
    int x1();
// actions												
	void y1(); void y4(); void y5(); void y6(); void y7(); void y12(); void y13(); 
    bool bType{false};	// delay type: false - transport; true - inertial;
    bool bX1{false};
    int nCurrent{0};
    int nDelay{0};		// tech. delay counter value
    LFsaAppl	*pFCall{nullptr};
    friend class FCallTransport;
    friend class FCallInertial;
};		

class FCallTransport :
	public LFsaAppl
{
public:
	void MooreAction();
	FCallTransport(FDiscreteTime	*pFDiscreteTime);
	FDiscreteTime	*pFDiscreteTime;
protected:
	int x1();
};

class FCallInertial :
	public LFsaAppl
{
public:
	void MooreAction();
	FCallInertial(FDiscreteTime	*pFDiscreteTime);
	FDiscreteTime	*pFDiscreteTime;
protected:
    int x1(); int x3();
};

#include "stdafx.h"
#include "FDiscreteTime.h"											
#include "VARFSA/SetVarFsaLibrary.h"
//=====================================================================
//		Delay model at the upper structural level of the view
//=====================================================================
LArc TBL_DiscreteTime[] = {
    LArc("st",	"st","^x12","y12"),	//
    LArc("st",	"ss","x12", "--"),	//
    LArc("ss",	"s1","x3",  "y7y6y13"),// transition to a single state
    LArc("ss",	"s0","^x3", "y4y5y13"),// transition to zero state
// creation of a nested automaton at the transition to a single state
    LArc("s0",	"s1","x3",  "y13"),    
// creation of a nested automaton at the transition to the zero state
    LArc("s1",	"s0","^x3", "y13"),    
    LArc()
};
FDiscreteTime::FDiscreteTime(string strNam, LArc* pTBL):
    LFsaAppl(pTBL, strNam, nullptr, nullptr)
{ }
													
FDiscreteTime::~FDiscreteTime(void) { if (pFCall) delete pFCall; }

bool FDiscreteTime::FInit() {										
    FCreationOfLinksForVariables();
    return true;
}

bool FDiscreteTime::FCreationOfLinksForVariables()
{
// Local variables
    pVarNegationY = CreateLocVar("negation", CLocVar::vtBool, "output inversion: 0-without inversion / 1-inversion");
    pVarType = CreateLocVar("type", CLocVar::vtBool, "delay type: 0-transp / 1-inertia");
    pVarY1 = CreateLocVar("y", CLocVar::vtBool, "local output");
    pVarX1 = CreateLocVar("x1", CLocVar::vtBool, "local input");
    pVarValue01 = CreateLocVar("value to 1", CLocVar::vtInteger, "delay value from 0 to 1");
    pVarValue10 = CreateLocVar("value to 0", CLocVar::vtInteger, "delay value from 1 to 0");
    pVarStrNameX1 = CreateLocVar("strNameX1", CLocVar::vtString, "name of external input variable (x)");
    pVarStrNameY1 = CreateLocVar("strNameY", CLocVar::vtString, "name of external output variable (y)");
    pVarIfNotX1 = CreateLocVar("not(x1)", CLocVar::vtBool, "1st input inversion: 0-without inversion / 1-inversion");
    string str;
    str = pVarStrNameX1->strGetDataSrc();
    if (str != "") { pVarX1 = pTAppCore->GetAddressVar(pVarStrNameX1->strGetDataSrc().c_str(), this);	}
    str = pVarStrNameY1->strGetDataSrc();
    if (str != "") { pVarY1 = pTAppCore->GetAddressVar(pVarStrNameY1->strGetDataSrc().c_str(), this);	}
    return true;
}
// predicates
int FDiscreteTime::x1() { return nCurrent == nDelay; }
//  
int FDiscreteTime::x3() {
    if (bool(pVarNegationY->GetDataSrc())) return !f();
    return f();
}
//
int FDiscreteTime::x12() { return pVarX1 != nullptr; }
//
bool FDiscreteTime::f() {
    bX1 = bool(pVarX1->GetDataSrc());
    if (bool(pVarIfNotX1->GetDataSrc())) bX1 = !bX1;
    return bX1;
}
// actions
// +1 to the current delay value
void FDiscreteTime::y1() { nCurrent++; }
// setting the delay value when switching from 0 to 1
void FDiscreteTime::y4() { nDelay = int(pVarValue01->GetDataSrc()); }
// setting output to zero
void FDiscreteTime::y5() { pVarY1->SetDataSrc(nullptr, 0.0); }
// setting output to unit
void FDiscreteTime::y6() { pVarY1->SetDataSrc(nullptr, 1); }
// setting the delay value when switching from 1 to 0
void FDiscreteTime::y7() { nDelay = int(pVarValue10->GetDataSrc()); }
//
void FDiscreteTime::y12() { FInit(); }
// creation, if a delay is determined, of the necessary nested automaton
void FDiscreteTime::y13() {
	nCurrent = 0;
	if (pFCall) { delete pFCall; pFCall = nullptr; }
	if (x1()) return;
	bType = pVarType->GetDataSrc();		// set delay type
	if (bType) pFCall = new FCallInertial(this);
	else pFCall = new FCallTransport(this);
	if (pFCall) pFCall->FCall(this);
}

void FDiscreteTime::MooreAction()
{
	string strState = FGetState();
	if (strState=="s0")	{ 
        y4(); y5();		// y4) setting the delay value when switching from 0 to 1; y5) set the output to zero
    }
	else if (strState=="s1") { 
        y7(); y6();		// y7) setting the delay value when switching from 1 to 0; y6) setting the output to one
    }
}
//=====================================================================
//				Transport delay
//=====================================================================
static LArc TBL_CallTransport[] = {
	LArc("s5","s5","^x1",	"--"),		//
	LArc("s5","00","x1",	"--"),		// 
	LArc()
};

FCallTransport::FCallTransport(FDiscreteTime	*pFI):
    LFsaAppl(TBL_CallTransport, "FCallTransport", nullptr, nullptr)
{
	pFDiscreteTime = pFI;
}
// . == 
int FCallTransport::x1() { return pFDiscreteTime->x1(); }
//
void FCallTransport::MooreAction()
{
	string strState = FGetState();
	if (strState=="s5")	{ pFDiscreteTime->y1(); }
}
//=====================================================================
//				Inertial delay
//=====================================================================
static LArc TBL_CallInertial[] = {
	LArc("s5",	"s5","^x1x3",	"--"),		//
	LArc("s5",	"00","x1x3",	"--"),		//
	LArc("s5",	"XX","^x3",	"--"),		//
	LArc()
};

FCallInertial::FCallInertial(FDiscreteTime	*pFI):
    LFsaAppl(TBL_CallInertial, "FCallInertial", nullptr, nullptr)
{
	pFDiscreteTime = pFI;
}
// . == 
int FCallInertial::x1() { return pFDiscreteTime->x1(); }
// input value (depends on the name of the current state of the main automaton)
int FCallInertial::x3() {
	string strState = FGetStateUp();
	bool bX = pFDiscreteTime->x3();
    if (strState == "s0") return bX;
    if (strState == "s1") return !bX;
	if (strState == "st") {
		string str = pFDiscreteTime->FGetNextState();
		bX = pFDiscreteTime->x3();
		if (!bX) {
			if (x1()) {
                if (str == "s0") return !bX;
                if (str == "s1") return bX;
			}
            else return true;
		}
		return true;
	}
	else return bX; 
}
//
void FCallInertial::MooreAction()
{
	string strState = FGetState();
	if (strState=="s5")	{ pFDiscreteTime->y1(); }
}


清单2.实现一个NAND门
#include "lfsaappl.h"

#include "../FDiscreteTime.h"
extern LArc TBL_DiscreteTime[];
class FIne :
	public FDiscreteTime
{
public:
    bool	FCreationOfLinksForVariables() override;
    LFsaAppl* Create(CVarFSA *pCVF) override { Q_UNUSED(pCVF) return new FIne(nameFsa); }
    bool FInit() override;
    FIne(string strNam, LArc* TBL = TBL_DiscreteTime);
    ~FIne(void);
	CVar *pVarX2;		//  
	CVar *pVarStrNameX2;	//    
	CVar *pVarIfNotX2;	//    
	virtual bool f() override;
protected:
    	int x12() override;
    	bool bX2;
};

#include "stdafx.h"
#include <Ine/FIne.h>
#include "VARFSA/SetVarFsaLibrary.h"

FIne::FIne(string strNam, LArc* pTBL):
    FDiscreteTime(strNam, pTBL)
{
    nTypeElement = FDiscreteTime::cvarINE;
}

FIne::~FIne(void) { }

bool FIne::FInit() {										
// 	 		
	FCreationOfLinksForVariables();
//	 										
	return true;										
}

bool FIne::FCreationOfLinksForVariables() {
//  
	FDiscreteTime::FCreationOfLinksForVariables();
	//      x1, x2
    pVarIfNotX2 = CreateLocVar("not(x2)", CLocVar::vtBool, " 2- : 0- /1-");
	pVarX2 = CreateLocVar("x2", CLocVar::vtBool, " 2- ");
    //  ,         x2
	pVarStrNameX2 = CreateLocVar("strNameX2", CLocVar::vtString, "  2- .(x)");
	// :   ,     
    string str = pVarStrNameX2->strGetDataSrc();
    if (str != "") { pVarX2 = pTAppCore->GetAddressVar(pVarStrNameX2->strGetDataSrc().c_str(), this); }
//
	return true;
}
//
int FIne::x12() { return FDiscreteTime::x12() && pVarX2 != nullptr; }
//
bool FIne::f() {
    //  1- 
    FDiscreteTime::f();
    //   
    bX2 = bool(pVarX2->GetDataSrc());
    if (bool(pVarIfNotX2->GetDataSrc())) bX2 = !bX2;
    //   : 
    return bX1&&bX2;
}


多亏了OOP,逻辑元素AND的模型代码不会明显小于“父”延迟的代码。而且,很大程度上取决于是否需要为AND元素的模型创建其他输入。如果在结构级别上模型与输入/输出的数量匹配,则代码将更小。因此,清单3显示了从与结构相似的AND-NOT元素模型生成的XOR门的实现代码。

清单3.异或网关的实现
#include <Ine/FIne.h>

extern LArc TBL_DiscreteTime[];
class FExlusiveOR :
    public FIne
{
public:
    LFsaAppl* Create(CVarFSA *pCVF) { return new FExlusiveOR(nameFsa); }
    FExlusiveOR(string strNam, LArc* TBL = TBL_DiscreteTime);
    ~FExlusiveOR(void);
protected:												
    bool f();
};

#include "stdafx.h"
#include "FExlusiveOR.h"

FExlusiveOR::FExlusiveOR(string strNam, LArc* pTBL):
    FIne(strNam, pTBL)
{
    nTypeElement = FDiscreteTime::cvarExlusiveOR;
}

FExlusiveOR::~FExlusiveOR(void) { }
//
bool FExlusiveOR::f() {
    FIne::f();
    return (bX1&&bX2)||(!bX1&&!bX2);
}


在这里,FExlusiveOR类的f()方法仅调用FIne类的f()方法来读取输入变量的值,然后将NAND函数的值与根据新类的逻辑函数计算出的值重叠。在图像和相似度中,可以创建任何其他两个输入逻辑元素的模型。

3.结论


为了实现任何数字电路,所谓的功能上完整的逻辑元件集就足够了。例如,它可以是一组AND,OR,NOT元素。我们研究了以下逻辑元素的实现-延迟,可以是反相器,AND-NOT和EXCLUSIVE OR元素。它们涉及功能完整集中的基本元素。为了实现和/或模拟任何方案,必须将其添加到库中,例如,添加OR-NOT元素或实现将通用自定义元素配置为功能上完整的元素。已经足够了。

因此,在上述模型的基础上,我们为VKPa环境提供了一个成熟的环境,用于数字电路的逻辑建模,使您可以从任何库元素生成任意数量的进程,对其进行配置并在它们之间建立连接。同时,与上述两种典型的逻辑建模方法(编译和事件)相比,仿真将更详细(考虑所有类型的延迟),更灵活(您可以分别配置元素)。它将不是一个专门的环境,因为软件过程的模型保持不变;它将与基于C ++语言使用的任何其他面向对象的编程环境一样通用。

还有更多关于...疼痛的信息。曾几何时,面对科学文献中的错误,或更准确地说,将诸如RS触发之类的关键逻辑元素的描述实际上是文盲的,甚至是很酷的电子工程师也不知道它如何详细工作的事实触发时,我花了很多时间来解决这个问题。我可以报告一下,在当前触发问题中,至少对我而言没有空白(请参阅详细信息[3])。因此,总的来说,没有任何变化是令人惊讶的。正如之前对触发器的表格描述所给出的那样,由于存在着臭名昭著的禁止状态,今天仍在给出它,并且它们仍然与他们抱怨退出禁止状态时触发器的不可预知的切换相同,因此它们仍然处于同一无知状态。尽管已经知道了对其行为进行足够准确描述的示例(例如,参见[4])。

的确,“您的行为美极了,主!” 不,在这类“ RS触发描述符”的头上……自动编程以及在VKPa环境中考虑的对逻辑电路建模的方法。而且,如果您返回本文的主题,那么例如,使用上述NAND元素模型,您可以轻松创建触发器模型并详细模拟其操作。包括考虑仅具有惯性类型的延迟的实际逻辑元素的属性。好吧,如果您需要触发器属性的形式证明,则可以在[5]中给出。

文献
1. ., ., . UML. . . : , 2007. – 493 .
2. ., ., . : . . – .: , 1988. – 309 .
3. . [ ], : habr.com/ru/post/484588 . . . ( 07.01.2020).
4. . . 2- . – .: , 2004. – 432.
5. .. . [ ], : cloud.mail.ru/public/HwsK/T95PMM8Ed . . . ( 01.02.2020).

All Articles