• 番外篇(3)矩阵模块与复用模块的设计细节


    对矩阵模块连接的要求

      求解矩阵微分方程时使用总线连接的形式更简洁,但实际编写时并没有那么简单。比如新建一个矩阵增益模块,我们希望在将其它模块连接到"矩阵增益模块"的输入时不用考虑一个矩阵增益模块里到底有几个单元增益模块,而是由模块的输入总线尺寸唯一确定。当然单元增益模块的具体数量还由给定的增益矩阵确定,以及矩阵加法模块可能有多个输入总线,矩阵模块内含的单元模块的具体数量有多种确定方式,具体细节见下文。
      还需要考虑的问题是,如果一个矩阵模块的输入总线尺寸无法确定,这就要求在连接矩阵模块时,必须先连接能确定总线尺寸的矩阵模块再连接不能确定的模块,这就要求模块之间的连接要遵循一定的顺序,不符合设计理念。也就是说,对于一个矩阵模块,我们既不希望在初始化时设置它的参数,也不希望在连接模块时考虑它的连接顺序。
      为了达到这一需求,需要将矩阵模块加入仿真器,模块连接完成后,在仿真器初始化过程中进一步确定所有矩阵模块的总线尺寸和内部单元模块数量。具体的算法如下

    for i in 4:-1:0
        for m in modules
            update(m)
    
    • 1
    • 2
    • 3

    如果4个矩阵模块的连接方式为A->B->C->D,其中只有A的总线尺寸已知,则正确的更新顺序就是A->B->C->D,但实际上用户代码中添加模块的顺序任意,最坏的情况是按DCBA的顺序添加,此时的更新过程为

    更新D失败;更新C失败;更新B成功;更新A成功;
    更新D失败;更新C成功;更新B成功;更新A成功;
    更新D成功;更新C成功;更新B成功;更新A成功;
    
    • 1
    • 2
    • 3

    可以看出这种算法效率较低,而且与单元模块的模块次序表有点像,但仍有不同。首先,初始化阶段的代码只执行一次,可以不用考虑执行效率,而模块次序表的执行要尽可能快;其次,矩阵模块在更新完以后要被打散并删除,没有必要建表。
      每个矩阵模块的更新分为两步(两种),第一步是确定输出总线的尺寸,第二步是与输入模块建立连接。输出总线尺寸的确定即意味着内部的单元模块已经生成。
      复用/解复用模块无法省略,否则,如果省略复用模块,将一个单元模块的输出连接到未知尺寸矩阵模块的输入时无法处理。此时一个矩阵模块的输入模块有两种,一种是同总线尺寸的矩阵模块,另一种是复用模块;同理一个矩阵模块的输出模块有两种,即矩阵模块和解复用模块。
      关于是将复用模块单独作为一个类还是作为矩阵模块的派生类的问题,如果作为矩阵模块的派生类,那么同样需要处理单元模块与未知尺寸矩阵模块相连的复杂问题;如果单独作为一个类,则需要根据输入是矩阵模块还是复用模块分类连接。目前是将复用模块单独作为一个类。
      如果将复用模块单独作为一个类,那么是否有必要将一个模块的所有成员变量,如模块名称、所属的仿真器指针等参数加入其中,以及是否有必要将模块加入仿真器等工作也是必须要考虑的问题。

    加入矩阵模块后的连接函数

      加入矩阵模块后,两个模块之间的连接函数变得复杂了起来,此时需要对原来的connect()函数进行大幅修改。为便于区分,如果两个模块之间使用单线连接,则函数名称改为connectU(),意为unit;如果使用总线连接则改为connectM(),意为matrix。函数名称更改后,修改版本号至V2,应用代码与V1版本不兼容,simucpp例程中的代码需要部分修改,逐渐向V2版本过渡。
      下面给出全部的连接函数重载。

    // 两个单元模块连接
    void connectU(PUnitModule m1, PUnitModule m2);
    // 组合模块内部的单元模块之间使用单线连接
    void connectU(PUnitModule m1, PPackModule m2, int n2=0);
    void connectU(PPackModule m1, int n1, PUnitModule m2);
    void connectU(PPackModule m1, PUnitModule m2);
    void connectU(PPackModule m1, int n1, PPackModule m2, int n2=0);
    void connectU(PPackModule m1, PPackModule m2, int n2=0);
    // 两个矩阵模块,或组合模块内部的矩阵模块之间使用总线连接
    void connectM(PMatModule m1, PMatModule m2);
    void connectM(PMatModule m1, PPackModule m2, int n2=0);
    void connectM(PPackModule m1, int n1, PMatModule m2);
    void connectM(PPackModule m1, PMatModule m2);
    void connectM(PPackModule m1, int n1, PPackModule m2, int n2=0);
    void connectM(PPackModule m1, PPackModule m2, int n2=0);
    // 单元模块与复用/解复用模块之间使用单线连接
    void connectU(PUnitModule m1, PMux m2, BusSize n2=BusSize());  // unit to mux
    void connectU(PDeMux m1, BusSize n1, PUnitModule m2);  // demux to unit
    void connectU(PDeMux m1, PUnitModule m2);  // demux to unit
    void connectU(PDeMux m1, BusSize n1, PPackModule m2, int n2=0);  // demux to pack
    void connectU(PDeMux m1, PPackModule m2, int n2=0);  // demux to pack
    void connectU(PDeMux m1, BusSize n1, PMux m2, BusSize n2=BusSize());  // demux to mux
    void connectU(PDeMux m1, PMux m2, BusSize n2=BusSize());  // demux to mux
    void connectU(PPackModule m1, int n1, PMux m2, BusSize n2=BusSize());  // pack to nux
    void connectU(PPackModule m1, PMux m2, BusSize n2=BusSize());  // pack to mux
    
    • 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

    其它细节

    • 连接解复用器与单元模块时,因为输入解复用器的矩阵模块可能还没有初始化,因此需要反过来让解复用器存储单元模块的指针。
  • 相关阅读:
    有用FPGA开发长光辰芯HR400BSI探测器的吗?有偿请教技术问题
    P8813 [CSP-J 2022] 乘方
    文心大模型写TodoList项目需求
    数据结构-排序
    接口文档规范
    神经网络系列---激活函数
    pandas 中的两种数据结构:Series, DataFrame
    PrimalScript通用脚本环境
    关于LocalDateTime的全局返回时间带“T“的时间格式处理
    英特尔oneAPI-用于异构计算的英特尔oneAPI
  • 原文地址:https://blog.csdn.net/qq_34288751/article/details/126324078