C++仿真微带电路

//微带线结构,激励为平面波激励。采用shape函数限制平面波在微带线和地之间
//高斯脉冲
//介质为微带结构
#define _CRT_SECURE_NO_DEPRECATE
#include <math.h>
#include <stdlib.h>
#include <stdio.h>


#define IE 62
#define JE 120
#define KE 14

#define ia 14
#define ja 15
#define ka 7
#define NFREQS 3
#define ktop 2
void main()
{
    double dx[IE][JE][KE], dy[IE][JE][KE], dz[IE][JE][KE];
    double ex[IE][JE][KE], ey[IE][JE][KE], ez[IE][JE][KE];
    double hx[IE][JE][KE], hy[IE][JE][KE], hz[IE][JE][KE];
    //double ix[IE][JE][KE], iy[IE][JE][KE], iz[IE][JE][KE];
    double gax[IE][JE][KE], gay[IE][JE][KE], gaz[IE][JE][KE];
    double gbx[IE][JE][KE], gby[IE][JE][KE], gbz[IE][JE][KE];
    int   n, i, j, k, ic, jc, kc, nsteps, npml;
    double ddz, ra_x, ra_y, dt, T, epsz, muz, pi;
    int ib, jb, kb;
    double  xn, xxn, xnum, xd;
    double t0, spread, pulse;
    double ez_inc[JE], hx_inc[JE];
    double ez_inc_low_m1, ez_inc_low_m2, ez_inc_high_m1, ez_inc_high_m2;

    double idxl[ia][JE][KE], idxh[ia][JE][KE];
    double ihxl[ia][JE][KE], ihxh[ia][JE][KE];
    double idyl[IE][ja][KE], idyh[IE][ja][KE];
    double ihyl[IE][ja][KE], ihyh[IE][ja][KE];
    double idzl[IE][JE][ka], idzh[IE][JE][ka];
    double ihzl[IE][JE][ka], ihzh[IE][JE][ka];
    int ixh, jyh, kzh;

    double gi1[IE], gi2[IE], gi3[IE];
    double gj1[JE], gj2[JE], gj3[JE];
    double gk1[KE], gk2[KE], gk3[KE];
    double fi1[IE], fi2[IE], fi3[IE];
    double fj1[JE], fj2[JE], fj3[JE];
    double fk1[KE], fk2[KE], fk3[KE];

    double curl_h, curl_e;

//    int ii, jj, kk;
//    double dist, xdist, ydist, zdist;

    int istart, iend, k_ref, i_ref;
    int j_patch_st, j_patch_end, j_ref;
    int i_patch_st, i_patch_end;
    double eps_sub;
    double shape[IE][KE], half_wv;
    FILE *fp;

    ic = IE / 2;
    jc = JE / 2;
    kc = KE / 2;
    //PML边界空间大小
    ib = IE - ia - 1;
    jb = JE - ja - 1;
    kb = KE - ka - 1;

    i_patch_st = ia + 5;
    i_patch_end = i_patch_st + 31;
    j_patch_end = jb - 5;
    j_patch_st = j_patch_end - 39;
    j_ref = j_patch_st - 30;
    k_ref = ktop - 1;


    pi = 3.14159;
    npml = 7;
    epsz = 8.8e-12;         //真空中的介电常数
    muz = 4 * pi*1.0e-7;    //真空中的磁导率
    ddz = 0.265e-3;             // 空间步长,单个波长中取20个网格
    dt = ddz / 6e8;           //时间步长
    ra_x = 0.6812;
    ra_y = 0.6625;            //x和y方向的网格因子
    eps_sub = 2.2;

    ez_inc_low_m1 = 0.0;
    ez_inc_low_m2 = 0.0;
    ez_inc_high_m1 = 0.0;
    ez_inc_high_m2 = 0.0;

    // Initialize the arrays
    for (j = 0; j < JE; j++){
        ez_inc[j] = 0.0;
        hx_inc[j] = 0.0;
        for (k = 0; k < KE; k++){
            for (i = 0; i < IE; i++){
                ex[i][j][k] = 0.0;
                ey[i][j][k] = 0.0;
                ez[i][j][k] = 0.0;
                dx[i][j][k] = 0.0;
                dy[i][j][k] = 0.0;
                dz[i][j][k] = 0.0;
                hx[i][j][k] = 0.0;
                hy[i][j][k] = 0.0;
                hz[i][j][k] = 0.0;
                gax[i][j][k] = 1.0;
                gay[i][j][k] = 1.0;
                gaz[i][j][k] = 1.0;
                gbx[i][j][k] = 0.0;
                gby[i][j][k] = 0.0;
                gbz[i][j][k] = 0.0;
            }
        }
    }
    //定义基板
    for (j = 0; j < JE; j++)
    {
        for (i = 0; i < IE; i++)
        {
            for (k = 0; k <= ktop; k++)
            {
                gax[i][j][k] = 1.0 / eps_sub;
                gay[i][j][k] = 1.0 / eps_sub;
                gaz[i][j][k] = 1.0 / eps_sub;
            }
        }
    }
    //底部加一层金属片
    for (i = 1; i < IE - 1; i++)
    {
        for (j = 1; j < JE - 1; j++)
        {
            k = 0;
            gax[i][j][k] = 0.0;
            gay[i][j][k] = 0.0;
        }
    }
    istart = ia + 13;
    iend = istart + 6;
    i_ref = istart + (iend - istart) / 2;
    half_wv = (iend - istart) / 2;

    for (i = istart; i <= iend; i++)
    {
        for (k = 0; k <= ktop; k++)
        {
            shape[i][k] = 1.0;
        }
    }

    //在K=ktop+1上增加导体导线
    for (j = 1; j <= j_patch_st; j++)
    {
        for (i = istart; i < iend - 1; i++)
        {
            gax[i][j][ktop + 1] = 0.0;
        }
        for (i = istart; i < iend - 1; i++)
        {
            gay[i][j][ktop + 1] = 0.0;
        }
    }
    //在ktop上加矩形贴片
    for (j = j_patch_st; j <= j_patch_end; j++)
    {
        for (i = ia + 1; i <= ib - 1; i++)
        {
            gax[i][j][ktop + 1] = 0.0;
        }
        for (i = ia + 1; i <= ib - 1; i++)
        {
            gay[i][j][ktop + 1] = 0.0;
        }
    }
    for (i = 0; i < ia; i++)
    {
        for (j = 0; j < JE; j++)
        {
            for (k = 0; k < KE; k++)
            {
                idxl[i][j][k] = 0.0;
                idxh[i][j][k] = 0.0;
                ihxl[i][j][k] = 0.0;
                ihxh[i][j][k] = 0.0;
            }
        }
    }
    for (i = 0; i < IE; i++)
    {
        for (j = 0; j < ja; j++)
        {
            for (k = 0; k < KE; k++)
            {
                idyl[i][j][k] = 0.0;
                idyh[i][j][k] = 0.0;
                ihyl[i][j][k] = 0.0;
                ihyh[i][j][k] = 0.0;
            }
        }
    }
    for (i = 0; i < IE; i++)
    {
        for (j = 0; j < JE; j++)
        {
            for (k = 0; k < ka; k++)
            {
                idzl[i][j][k] = 0.0;
                idzh[i][j][k] = 0.0;
                ihzl[i][j][k] = 0.0;
                ihzh[i][j][k] = 0.0;
            }
        }
    }

    //Boundry Conditions

    for (i = 0; i < IE; i++)
    {
        gi1[i] = 0.0;
        fi1[i] = 0.0;
        gi2[i] = 1.0;
        fi2[i] = 1.0;
        gi3[i] = 1.0;
        fi3[i] = 1.0;
    }
    for (j = 0; j < JE; j++)
    {
        gj1[j] = 0.0;
        fj1[j] = 0.0;
        gj2[j] = 1.0;
        fj2[j] = 1.0;
        gj3[j] = 1.0;
        fj3[j] = 1.0;
    }
    for (k= 0; k < KE; k++)
    {
        gk1[k] = 0.0;
        fk1[k] = 0.0;
        gk2[k] = 1.0;
        fk2[k] = 1.0;
        gk3[k] = 1.0;
        fk3[k] = 1.0;
    }
    //PML边界设置
    for (i = 0; i < npml; i++)
    {
        xnum = npml - i;
        xd = npml;
        xxn = xnum / xd;
        xn = 0.33*pow(xxn, 3.0);
        fi1[i] = xn;
        fi1[IE - 1 - i] = xn;
        gi2[i] = 1.0 / (1.0 + xn);
        gi2[IE - i - 1] = 1.0 / (1.0 + xn);
        gi3[i] = (1.0 - xn) / (1.0 + xn);
        gi3[IE - i - 1] = (1.0 - xn) / (1.0 + xn);

        xxn = (xnum - 0.5) / xd;
        xn = 0.25*pow(xxn, 3.0);
        gi1[i] = xn;
        gi1[IE - i - 2] = xn;
        fi2[i] = 1.0 / (1.0 + xn);
        fi2[IE - 2 - i] = 1.0 / (1.0 + xn);
        fi3[i] = (1.0 - xn) / (1.0 + xn);
        fi3[IE - i - 2] = (1.0 - xn) / (1.0 + xn);
    }
    
    for (j = 0; j < npml; j++)
    {
        xnum = npml - j;
        xd = npml;
        xxn = xnum / xd;
        xn = 0.33*pow(xxn, 3.0);
        fj1[j] = xn;
        fj1[JE - 1 - j] = xn;
        gj2[j] = 1.0 / (1.0 + xn);
        gj2[JE - j - 1] = 1.0 / (1.0 + xn);
        gj3[j] = (1.0 - xn) / (1.0 + xn);
        gj3[JE - j - 1] = (1.0 - xn) / (1.0 + xn);

        xxn = (xnum - 0.5) / xd;
        xn = 0.33*pow(xxn, 3.0);
        gj1[j] = xn;
        gj1[JE - j - 2] = xn;
        fj2[j] = 1.0 / (1.0 + xn);
        fj2[JE - 2 - j] = 1.0 / (1.0 + xn);
        fj3[j] = (1.0 - xn) / (1.0 + xn);
        fj3[JE - 2 - j] = (1.0 - xn) / (1.0 + xn);
    }
    //在K方向上,只有向上的方向设置了PML
    //向下的方向由于金属板的存在而不需要另设边界
    for (k = 0; k < npml; k++)
    {
        xnum = npml - k;
        xd = npml;
        xxn = xnum / xd;
        xn = 0.33*pow(xxn, 3.0);
        //fj1[j] = xn;
        fk1[KE - 1 - k] = xn;
        //gj2[j] = 1.0 / (1.0 + xn);
        gk2[KE - k - 1] = 1.0 / (1.0 + xn);
        //gj3[j] = (1.0 - xn) / (1.0 + xn);
        gk3[KE - k - 1] = (1.0 - xn) / (1.0 + xn);

        xxn = (xnum - 0.5) / xd;
        xn = 0.33*pow(xxn, 3.0);
        //gj1[j] = xn;
        gk1[KE - k - 2] = xn;
        //fj2[j] = 1.0 / (1.0 + xn);
        fk2[KE - 2 - k] = 1.0 / (1.0 + xn);
        //fj3[j] = (1.0 - xn) / (1.0 + xn);
        fk3[KE - 2 - k] = (1.0 - xn) / (1.0 + xn);
    }

    t0 = 150.0;
    spread = 25;
    T = 0;
    nsteps = 1;

    while (nsteps > 0)
    {
        printf("nsteps -->");
        scanf("%d", &nsteps);
        printf("%d\n", nsteps);

        for (n = 1; n < nsteps; n++)
        {
            T = T + 1;

            //Start of the Main FDTD loop

            //一维高斯脉冲激励用于平面波拓展
            for (j = 1; j < JE; j++)
            {
                ez_inc[j] = gj3[j] * ez_inc[j] + gj2[j] * (0.5*ra_y / eps_sub)*(hx_inc[j - 1] - hx_inc[j]);
            }
            //Source
            pulse = exp(-0.5*pow((t0 - T) / spread, 2.0));
            ez_inc[ja - 2] = pulse;

            //Boundary condition for the incident buffer
            //一维吸收边界
            ez_inc[0] = ez_inc_low_m2;
            ez_inc_low_m2 = ez_inc_low_m1;
            ez_inc_low_m1 = ez_inc[1];
            ez_inc[JE - 1] = ez_inc_high_m2;
            ez_inc_high_m2 = ez_inc_high_m1;
            ez_inc_high_m1 = ez_inc[JE - 2];

            //Calculate the Dx field
            for (i = 1; i < ia; i++)
            {
                for (j = 1; j < JE; j++)
                {
                    for (k = 1; k < KE; k++)
                    {
                        curl_h = (ra_y* (hz[i][j][k] - hz[i][j - 1][k]) - hy[i][j][k] + hy[i][j][k - 1]);
                        idxl[i][j][k] = idxl[i][j][k] + curl_h;
                        dx[i][j][k] = gj3[j] * gk3[k] * dx[i][j][k] + gj2[j] * gk2[k] * 0.5*(curl_h + gi1[i] * idxl[i][j][k]);
                    }
                }
            }

            for (i = ia; i <= ib; i++)
            {
                for (j = 1; j < JE; j++)
                {
                    for (k = 1; k < KE; k++)
                    {
                        curl_h = (ra_y*(hz[i][j][k] - hz[i][j - 1][k]) - hy[i][j][k] + hy[i][j][k - 1]);
                        dx[i][j][k] = gj3[j] * gk3[k] * dx[i][j][k] + gj2[j] * gk2[k] * 0.5*curl_h;
                    }
                }
            }

            for (i = ib+1; i < IE; i++)
            {
                ixh = i - ib - 1;
                for (j = 1; j < JE; j++)
                {
                    for (k = 1; k < KE; k++)
                    {
                        curl_h = (ra_y* (hz[i][j][k] - hz[i][j - 1][k]) - hy[i][j][k] + hy[i][j][k - 1]);
                        idxh[ixh][j][k] = idxh[ixh][j][k] + curl_h;
                        dx[i][j][k] = gj3[j] * gk3[k] * dx[i][j][k] + gj2[j] * gk2[k] * 0.5*(curl_h + gi1[i] * idxh[i][j][k]);
                    }
                }
            }

            //Calculate the Dy field

            for (i = 1; i < IE; i++)
            {
                for (j = 1; j < ja; j++)
                {
                    for (k = 1; k < KE; k++)
                    {
                        curl_h = (-ra_x* (hz[i][j][k] - hz[i-1][j ][k]) + hx[i][j][k] - hx[i][j][k - 1]);
                        idyl[i][j][k] = idyl[i][j][k] + curl_h;
                        dy[i][j][k] = gi3[i] * gk3[k] * dy[i][j][k] + gi2[i] * gk2[k] * 0.5*(curl_h + gj1[j] * idyl[i][j][k]);
                    }
                }
            }

            for (i =1; i <IE; i++)
            {
                for (j = ja; j <= jb; j++)
                {
                    for (k = 1; k < KE; k++)
                    {
                        curl_h = (-ra_x*(hz[i][j][k] - hz[i-1][j][k]) + hx[i][j][k] - hx[i][j][k - 1]);
                        dy[i][j][k] = gi3[i] * gk3[k] * dy[i][j][k] + gi2[i] * gk2[k] * 0.5*curl_h;
                    }
                }
            }
            for (i = 1; i < IE; i++){
                for (j = jb + 1; j < JE; j++){
                    jyh = j - jb - 1;
                    for (k = 1; k < KE; k++){
                        curl_h = (hx[i][j][k] - hx[i][j][k - 1] - ra_x*(hz[i][j][k] + hz[i - 1][j][k]));
                        idyh[i][jyh][k] = idyh[i][jyh][k] + curl_h;
                        dy[i][j][k] = gi3[i] * gk3[k] * dy[i][j][k] + gi2[i] * gk2[k] * 0.5*(curl_h + gj1[j] * idyh[i][jyh][k]);
                    }
                }
            }
            
            //Calculate the Dz field

            for (i = 1; i < IE; i++)
            {
                for (j = 1; j < JE; j++)
                {
                    for (k = 0; k < ka; k++)
                    {
                        curl_h = (ra_x*(hy[i][j][k] - hy[i - 1][j][k]) - ra_y*(hx[i][j][k] + hx[i][j - 1][k]));
                        idzl[i][j][k] = idzl[i][j][k] + curl_h;
                        dz[i][j][k] = gi3[i] * gj3[j] * dz[i][j][k] + gi2[i] * gj2[j] * 0.5*(curl_h + gk1[k] * idzl[i][j][k]);
                    }
                }
            }

            for (i = 1; i < IE; i++)
            {
                for (j = 1; j < JE; j++)
                {
                    for (k = ka; k <= kb; k++)
                    {
                        curl_h = (ra_x*(hy[i][j][k] - hy[i - 1][j][k]) - ra_y*(hx[i][j][k] + hx[i][j - 1][k]));
                        dz[i][j][k] = gi3[i] * gj3[j] * dz[i][j][k] + gi2[i] * gj2[j] * 0.5*curl_h;
                    }
                }
            }

            for (i = 1; i < IE; i++)
            {
                for (j = 1; j < JE; j++)
                {
                    for (k = kb + 1; k < KE; k++)
                    {
                        kzh = k - kb - 1;
                        curl_h = (ra_x*(hy[i][j][k] - hy[i - 1][j][k]) - ra_y*(hx[i][j][k] + hx[i][j - 1][k]));
                        idzh[i][j][kzh] = idzh[i][j][kzh] + curl_h;
                        dz[i][j][k] = gi3[i] * gj3[j] * dz[i][j][k] + gi2[i] * gj2[j] * 0.5*(curl_h + gk1[k] * idzh[i][j][kzh]);
                    }
                }
            }

            //修正 Dz
            for (i = istart; i <= iend; i++)
            {
                for (k = 0; k <= ktop; k++)
                {
                    dz[i][ja][k] = dz[i][ja][k] + (0.5 / eps_sub)*shape[i][k] * hx_inc[ja - 1];
                }

                // Calculate the E from D field
                for (i = 1; i < IE - 1; i++)
                {
                    for (j = 1; j < JE - 1; j++)
                    {
                        for (k = 1; k < KE - 1; k++)
                        {
                            ex[i][j][k] = gax[i][j][k] * (dx[i][j][k]);
                            ey[i][j][k] = gay[i][j][k] * (dy[i][j][k]);
                            ez[i][j][k] = gaz[i][j][k] * (dz[i][j][k]);
                        }
                    }
                }

                // Calculate the incident field
                //一维高斯脉冲激励用于平面波扩展,计算磁场
                for (j = 0; j < JE - 1; j++)
                {
                    hx_inc[j] = fj3[j] * hx_inc[j] + 0.5*fj2[j] * (ez_inc[j] - ez_inc[j + 1]);
                }

                //Calculate the Hx field

                for (i = 0; i < ia; i++)
                {
                    for (j = 0; j < JE - 1; j++)
                    {
                        for (k = 0; k < KE - 1; k++)
                        {
                            curl_e = (ey[i][j][k + 1] - ey[i][j][k] - ra_y*(ez[i][j + 1][k] + ez[i][j][k]));
                            ihxl[i][j][k] = ihxl[i][j][k] + curl_e;
                            hx[i][j][k] = fj3[j] * fk3[k] * hx[i][j][k] + fj2[j] * fk2[k] * 0.5*(curl_e + fi1[i] * ihxl[i][j][k]);
                        }
                    }
                }

                for (i = ia; i <= ib; i++)
                {
                    for (j = 0; j < JE - 1; j++)
                    {
                        for (k = 0; k < KE - 1; k++)
                        {
                            curl_e = (ey[i][j][k + 1] - ey[i][j][k] - ra_y*(ez[i][j + 1][k] + ez[i][j][k]));
                            hx[i][j][k] = fj3[j] * fk3[k] * hx[i][j][k] + fj2[j] * fk2[k] * 0.5*curl_e;
                        }
                    }
                }

                for (i = ib + 1; i < IE; i++)
                {
                    ixh = i - ib - 1;
                    for (j = 0; j < JE - 1; j++)
                    {
                        for (k = 0; k < KE - 1; k++)
                        {
                            curl_e = (ey[i][j][k + 1] - ey[i][j][k] - ra_y*(ez[i][j + 1][k] + ez[i][j][k]));
                            ihxh[ixh][j][k] = ihxh[ixh][j][k] + curl_e;
                            hx[i][j][k] = fj3[j] * fk3[k] * hx[i][j][k] + fj2[j] * fk2[k] * 0.5*(curl_e + fi1[i] * ihxh[ixh][j][k]);
                        }
                    }
                }

                // 修正 Hx
                for (i = istart; i <= iend; i++)
                {
                    for (k = 0; k <= ktop; k++)
                    {
                        hx[i][ja - 1][k] = hx[i][ja - 1][k] + (0.5 / eps_sub)*shape[i][k] * ez_inc[ja];
                    }
                }

                // Calculate the Hy field

                for (i = 0; i < IE - 1; i++)
                {
                    for (j = 0; j < ja; j++)
                    {
                        for (k = 0; k < KE - 1; k++)
                        {
                            curl_e = (ra_x*(ez[i + 1][j][k] - ez[i][j][k]) - ex[i][j][k + 1] + ex[i][j][k]);
                            ihyl[i][j][k] = ihyl[i][j][k] + curl_e;
                            hy[i][j][k] = fi3[i] * fk3[k] * hy[i][j][k] + fi2[i] * fk3[k] * 0.5*(curl_e + fj1[j] * ihyl[i][j][k]);
                        }
                    }
                }

                for (i = 0; i < IE - 1; i++)
                {
                    for (j = ja; j <= jb; j++)
                    {
                        for (k = 0; k < KE - 1; k++)
                        {
                            curl_e = (ra_x*(ez[i + 1][j][k] - ez[i][j][k]) - ex[i][j][k + 1] + ex[i][j][k]);
                            hy[i][j][k] = fi3[i] * fk3[k] * hy[i][j][k] + fi2[i] * fk3[k] * 0.5*curl_e;
                        }
                    }
                }

                for (i = 0; i < IE - 1; i++)
                {
                    for (j = jb + 1; j < JE; j++)
                    {
                        jyh = j - jb - 1;
                        for (k = 0; k < KE - 1; k++)
                        {
                            curl_e = (ra_x*(ez[i + 1][j][k] - ez[i][j][k]) - ex[i][j][k + 1] + ex[i][j][k]);
                            ihyh[i][jyh][k] = ihyh[i][jyh][k] + curl_e;
                            hy[i][j][k] = fi3[i] * fk3[k] * hy[i][j][k] + fi2[i] * fk3[k] * 0.5*(curl_e + fj1[j] * ihyh[i][jyh][k]);
                        }
                    }
                }


                // Calculate the Hz field

                for (i = 0; i < IE - 1; i++)
                {
                    for (j = 0; j < JE - 1; j++)
                    {
                        for (k = 0; k < ka; k++)
                        {
                            curl_e = (ra_y*(ex[i][j + 1][k] - ex[i][j][k]) - ra_x*(ey[i + 1][j][k] + ey[i][j][k]));
                            ihzl[i][j][k] = ihzl[i][j][k] + curl_e;
                            hz[i][j][k] = fi3[i] * fj3[j] * hz[i][j][k] + fi2[i] * fj2[j] * 0.5*(curl_e + fk1[k] * ihzl[i][j][k]);
                        }
                    }
                }

                for (i = 0; i < IE - 1; i++)
                {
                    for (j = 0; j < JE - 1; j++)
                    {
                        for (k = ka; k <= kb; k++)
                        {
                            curl_e = (ra_y*(ex[i][j + 1][k] - ex[i][j][k]) - ra_x*(ey[i + 1][j][k] + ey[i][j][k]));
                            hz[i][j][k] = fi3[i] * fj3[j] * hz[i][j][k] + fi2[i] * fj2[j] * 0.5*curl_e;
                        }
                    }
                }

                for (i = 0; i < IE - 1; i++)
                {
                    for (j = 0; j < JE - 1; j++)
                    {
                        for (k = kb + 1; k < KE; k++)
                        {
                            kzh = k - kb - 1;
                            curl_e = (ra_y*(ex[i][j + 1][k] - ex[i][j][k]) - ra_x*(ey[i + 1][j][k] + ey[i][j][k]));
                            ihzh[i][j][kzh] = ihzh[i][j][kzh] + curl_e;
                            hz[i][j][k] = fi3[i] * fj3[j] * hz[i][j][k] + fi2[i] * fj2[j] * 0.5*(curl_e + fk1[k] * ihzh[i][j][kzh]);
                        }
                    }
                }
            }

            //End of the main FDTD loop
            //Write the E field out to a file "Ez"
            fp = fopen("Ez.txt", "w");
            for (j = 0; j < JE; j++)
            {
                for (i = 0; i < IE; i++)
                {
                    fprintf(fp, "%9.6f", ez[i][j][ktop]);
                }
                fprintf(fp, "\n");
            }
            fclose(fp);

            printf("T=%4.0f \n",T);
        }
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
定义数据结构如下: typedef struct tagMyNode { Mytype type; //元件类型 MySubtype Subtype; //元件子类型 tagMyNode* input1; //输入端1 tagMyNode* input2; //输入端1 tagMyNode* output1; //输出端1 UINT input1value; //输入端input1的值 UINT input2value; //输入端input2的值 UINT output1value; //输出端output1的值 int inputs; //当前已经有几个输入端有值 int number; //对于输入结点的序号 CPoint Orgpoint; //记录元件左上角位置 int width; //记录元件宽度 int height; //记录元件高度 }MyNode;  元件类型:元件类型Mytype type中Mytype是一个枚举类型定义如下: enum Mytype { Node, //结点 Gate, //门 }; 分为两种类型:Node结点和Gate门。  元件子类型:元件子类型MySubtype Subtype中MySubtype也是一个枚举类 型,定义如下: enum MySubtype { Input, //输入端 Output, //输出端 ANDGate, //与门 ORGate, //或门 NOTGate, //非门 NORGate, //或非门 NANDGate, //与非门 XORGate, //异或门 };  指针连接: tagMyNode* input1; tagMyNode* input2; tagMyNode* output1 是指向此结点的指针。由于元件之间是要相互连接的,于是设置这几个指针用于元件之间的连接。其中特殊情况有: 非门:由于非门只有一个输入端,所以非门不用tagMyNode* input2; 输入结点:输入结点只有一个链接端(这里称之为触点),采用tagMyNode* output1 输出结点:同输入结点,只有一个触点,采用tagMyNode* input1;  保存触点值:由于要进行仿真计算,所以还需保存各个触点的值: UINT input1value; UINT input2value; UINT output1value; 同指针连接,有3种特殊情况: 非门:不用UINT input2value; 输入结点:采用UINT output1value; 输出结点:采用UINT input1value;  进位标志:int inputs; 在进行仿真计算时,要用进位标志辅助计算。如与门只有在两个输入端都有值时,即inputs==2时,才能进位。  输入结点序号:int number; 每个输入结点都有不同的序号,从1开始递增。  元件位置和大小: CPoint Orgpoint; int width; int height; Orgpoint用于记录元件在视图中左上角的坐标 width用于记录元件宽度 height用于记录元件高度  电路图编辑模块 电路图编辑模块又分为两个子模块:鼠标放置元件模块,鼠标连接元件模块 首先在工具栏中可以选择这两种状态,如图4 图4 在按钮上单击可以切换状态。 定义一个枚举类型MyStatus来记录当前状态: enum MyStatus { NONE, //鼠标连接元件状态 ANDGATE, ORGATE, NOTGATE, NORGATE, NANDGATE, XORGATE, NODEINPUT, NODEOUTPUT }; MyStatus Status; 其中:NONE为鼠标连接状态,其他为鼠标放置状态。  鼠标放置元件模块 其算法如图5: 图5  DrawObject函数: 首先根据Status的状态,即六个门,两个端结点。共8种来调用DrawObject函数  引入准备好的八张位图(六个门,两个端) CBitmap MyBitMap; MyBitMap.LoadBitmap (nID);  将引入的位图拷贝入窗体窗户区 BITMAP bmpInfo; MyBitMap.GetBitmap (&bmpInfo); pOldBitmap=dc.SelectObject (&MyBitMap); ClientDC.BitBlt (point.x ,point.y,bmpInfo.bmWidth ,bmpInfo.bmHeight,&dc,0,0,SRCAND); dc.SelectObject (pOldBitmap);  用全局变量bmWidth和bmHeight来保存元件的宽度和高度 bmWidth=bmpInfo.bmWidth ; bmHeight=bmpInfo.bmHeight ;  CreateMyObject函数 函数声明为:CreateMyObject(Mytype type, MySubtype Subtype, CPoint point)  初始化元件 MyNode* pNode=new MyNode; pNode->type =type; pNode->Subtype =Subtype; pNode->input1 =0; pNode->input2 =0; pNode->output1 =0; pNode->output2 =0; pNode->Orgpoint =point; pNode->width =bmWidth; pNode->height =bmHeight; pNode->input1value =0; pNode->input2value =0; pNode->output1value =0; pNode->inputs =0;  如果创建的元件为输入结点,则要创建并画输入结点前的序号,这里 采用一个全局数组CArray<CPoint,CPoint> numpoint来记录结点前序号。 if(Subtype==Input) { //当创建Input时加入点到numpoint数组中 numpoint.Add (CPoint(point.x-15,point.y)); pNode->number =numpoint.GetSize (); //创建时重绘序号 redrawnum(); } 而redrawnum()函数就是将所有输入结点前的序号重绘。  最后将元件加入到全局链表CList<MyNode*,MyNode*> MyList中。 MyList.AddTail (pNode);  鼠标连接元件模块 鼠标连接元件模块分为三个过程模块:鼠标移动模块,鼠标按下模块,鼠标抬起模块。  鼠标移动模块 其算法如图6 图6 代码如下: void CMyView::OnMouseMove(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default //此时必然是非画图状态,所以status==NONE; if(Status==NONE) { //当前点在某个物件上吗? 并且 //当前点在该物件触点上吗? if(IsPointInObject(point) && IsPointInPut(point)) { //全局变量pNodeNow是在IsPointInObject()这个函数里面记录的 //circlepoint和put是在IsInInput1() IsInInput2() IsInOutput1() //这三个函数中记录的 //判断此时触点时否己连接非常重要 if(IsPutLinked()) { //如果此时触点己连接,则退出 return; } //此时鼠标移进触点 //当前是连接态吗? if(IsLink) { //连接态画图 LinkStatusDraw(point); } //开启画圆圈态 IsDrawCircle=TRUE; //画圆圈 DrawMyCircle(); } else//此时鼠标移出触点 { //如果此时已画圆圈,则要擦除圆圈 if(IsDrawCircle==TRUE) { EraserMyCircle(); //关闭画圆圈状态 IsDrawCircle=FALSE; //重绘连接线 moveoutredrawline(); //重绘圆圈所在的那个物件,因为擦除圆圈的时候可能擦除了部分物件 //------------------- redrawMyObject(pNodeNow); //如果此时是连接状态,连接态画图 } if(IsLink) { //连接态画图 LinkStatusDraw(point); } } } CView::OnMouseMove(nFlags, point); }  两个关键状态:可连接态IsDrawCircle和正在连接态IsLink  可连接态IsDrawCircle 当且仅当鼠标移动到某个元件上的某个尚未连接的触点上,才开启可连接态IsDrawCircle。之所以取名IsDrawCircle是因为此时会在鼠标停留的尚未连接的触点上画一个黑色小圆圈。 当鼠标移动离开触点,可连接态IsDrawCircle关闭。  正在连接态IsLink 当鼠标按下(见图5)并且此时可连接态IsDrawCircle开启(为TRUE)时正在连接态IsLink开启。  判断当前点是否在某个元件函数:IsPointInObject() 其算法如图7 图7  判断当前点是否在该元件触点上函数:IsPointInPut() 其算法如图8 图8 与门与其它5个门有所不同,与门只有一个输入端,所以要分开来判断 对于输入结点,则判断当前点是否在第一个输出端触点。 对于输出结点,则判断当前点是否在第一个输入端触点。 输入结点和输出结点的这样判断,一眼看上去似乎反了,但实际上有利于整个程序的编写。可以简单地这样分类:总共只有两种端,一种输入,一种输出。 这样,我们就可以将判断触点分为三个函数: IsInInput1() IsInInput2() IsInOutput1() 拿IsInInput1()来分析: centerpoint=GetCirclePoint(Input_1); if(IsInArea(point)) { //说明此时就在触点Input_1,用全局变量put记录下来 put=Input_1; //如果当前点在,则要保存触点中心点 circlepoint=centerpoint; return TRUE; } else { //如果移出触点,肯定不要再保存中心点 return FALSE; } 首先,调用函数GetCirclePoint()来取得当前触点的中心点。然后调用IsInArea(point)函数来判断当前点point是否在以当前触点中心点为中心的矩形区域内。如果是,则用一个全局枚举变量put来记录来前触点是两个输入端和一个输出端中哪一个。 我们看这个枚举类型: enum Myput { Input_1, Input_2, Output_1 }; 接下来用一个全局变量circlepoint来记录当前触点中心点。再返回真。 如果当前点不在以当前触点中心点为中心的矩形区域内,则返回假。这时千万不能记录当前触点中心点。这点不注意会出大错。  判断当前触点是否已连接函数:IsPutLinked() BOOL CMyView::IsPutLinked() { switch(put) { case Input_1: if(pNodeNow->input1 !=0) return TRUE; break; case Input_2: if(pNodeNow->input2 !=0) return TRUE; break; case Output_1: if(pNodeNow->output1 !=0) return TRUE; } return FALSE; } 这里根据全局变量put的类型和全局变量pNodeNow所指向的元件, 就可以判断当前元件的当前触点是否已连接。如果连接相应指针不为0。返回真,否则返回假。  连接态画图函数:LinkStatusDraw() void CMyView::LinkStatusDraw(CPoint point) { CClientDC clientDC(this); CPen whitepen(PS_SOLID,1,RGB(255,255,255)); CPen* pOldPen; pOldPen=clientDC.SelectObject (&whitepen); clientDC.MoveTo (startpoint); clientDC.LineTo (lastpoint); clientDC.SelectObject (pOldPen); CPen redpen(PS_DOT ,1,RGB(255,0,0)); pOldPen=clientDC.SelectObject (&redpen); clientDC.MoveTo (startpoint); clientDC.LineTo (point); clientDC.SelectObject (pOldPen); lastpoint=point; //重绘所有输入结点前的序号 redrawnum(); //重绘连接线 LinkLineRedraw(startpoint,point); //重绘物件 lineRedraw(startpoint,point); } 这里,startpoint是鼠标按下开始连接时起始元件触点中心点坐 标,lastpoint是上一次鼠标移动所停留的点。为了实在连接时鼠标移动 的动画效果,我们要先擦除上一次移动画的线(用白笔),然后再从startpoint到当前点point画线。移动时由于不信的擦除重画,可能将先前已画的元件,输入结点前的序号,和已经连接好的线擦除。于是我们需要重绘。 重绘所有输入结点前的序号 redrawnum(); void CMyView::redrawnum() { CClientDC dc(this); char buffer[20]; CPoint point; //重绘所有Input前的序号 for(int i=0;i<numpoint.GetSize ();i++) { //将数字转换成字符,存于buffer中 _itoa(i+1,buffer,10); point=numpoint.GetAt (i); dc.TextOut (point.x ,point.y ,buffer); } } 由于每创建一个输入结点,就要相应地记录一个序号。这个序号的位置点记录在numpoint这个数组中。数组声明如下: CArray<CPoint,CPoint> numpoint; 而数组的下标加1就为序号。 所以每次重绘为了方便,将所有序号都重绘。 重绘连接线 void CMyView::LinkLineRedraw(CPoint startpoint, CPoint point) { //将起点startpoint到终点point扩充成一个矩形drawrect CRect drawrect(startpoint,point); //rect用于产生连接线最大矩形 CRect rect; //rectInter用于计算两个矩形的相交区域 CRect rectInter; //point1和point2用于产生连接线最大矩形 CPoint point1; CPoint point2; drawrect.NormalizeRect (); drawrect.InflateRect (1,1); //遍历MyPointList链表 POSITION pos=MyPointList.GetHeadPosition (); while(pos!=0) { //pPointArray用于指向点数组对象首址 CArray<CPoint,CPoint>* pPointArray=MyPointList.GetNext (pos); point1=pPointArray->GetAt (0); switch(pPointArray->GetSize ()) { //分两种情况 :2个点和4,5个点的情况 case 2: //2个点时 point2=pPointArray->GetAt (1); break; default: //4,5个点时 point2=pPointArray->GetAt (3); } //用point1和point2设置矩形rect rect.left =point1.x ; rect.top =point1.y; rect.right =point2.x; rect.bottom =point2.y; rect.NormalizeRect (); rect.InflateRect (1,1); //如果两个矩形相交,则要重绘 if(rectInter.IntersectRect (&drawrect,&rect)) { DrawLinkLine(pPointArray); } } } 主要的算法思想是:将起点startpoint到当前点point扩充成一个矩形drawrect,然后遍历连接线链表,将每根连接线扩充成一个矩形rect,再判断这两个矩形是否相交,若相交,则需要重绘这根连接线。 连接线链表声明如下: CList<CArray<CPoint,CPoint>*,CArray<CPoint,CPoint>*> MyPointList; 链表中每个结点是一个数组对象的地址,而这个数组中每个元素是一个点。这样一个数组就表示了一根连接线,而一个链表可以遍历所以连接线。  画提示连接的小圆圈函数:DrawMyCircle() void CMyView::DrawMyCircle() { //此时全局变量circlepoint记录了要画圆圈的 //而pNodeNow指向了当前的物件 //将物件坐标中的circlepoint转换成VIEW中的坐标 int x,y; x=pNodeNow->Orgpoint .x +circlepoint.x; y=pNodeNow->Orgpoint .y +circlepoint.y; CClientDC dc(this); //创建一个黑色的画刷 CBrush brush(RGB(0,0,0)); //创建指针pOldBrush用于保存原来的画刷 CBrush* pOldBrush; //将黑色的画刷选进设备装置DC,并用pOldBrush保存原来的画刷 pOldBrush=dc.SelectObject (&brush); //画一个圆圈,圆心是(x,y) //半径是4 dc.Ellipse (x-4,y-4,x+4,y+4); //将原来的画刷选回 dc.SelectObject (pOldBrush); } 由于全局变量circlepoint保存的是元件内部的相对坐标,需要将它 转换成视图中的坐标 x=pNodeNow->Orgpoint .x +circlepoint.x; y=pNodeNow->Orgpoint .y +circlepoint.y; 以上两句完成坐标的转换。 然后以(x,y)为圆心,4为半径,画一个黑色小圆圈 dc.Ellipse (x-4,y-4,x+4,y+4)  擦除小圆圈函数:EraserMyCircle() void CMyView::EraserMyCircle() { int x,y; x=pNodeNow->Orgpoint .x +circlepoint.x; y=pNodeNow->Orgpoint .y +circlepoint.y; CClientDC dc(this); CPen whitepen(PS_SOLID,1,RGB(255,255,255)); CPen* pOldPen; pOldPen=dc.SelectObject (&whitepen); dc.Ellipse (x-4,y-4,x+4,y+4); dc.SelectObject (pOldPen); } 与画小圆圈不同的是,擦除时要选择白色的笔和白色的画刷(默认) CPen whitepen(PS_SOLID,1,RGB(255,255,255)); CPen* pOldPen; pOldPen=dc.SelectObject (&whitepen); 以上3句选择白色的笔。  鼠标移开触点重绘连接线函数:moveoutredrawline() 为什么需要这个函数,原因是在鼠标称出触点后,此时要擦除刚才画 的小圆圈,而如果此时已经生成了连接线,则会擦除掉连接线的一小部分。于是需要这个函数。 void CMyView::moveoutredrawline() { int x,y; x=pNodeNow->Orgpoint .x +circlepoint.x; y=pNodeNow->Orgpoint .y +circlepoint.y; CPoint point1; CPoint point2; point1.x=x-4; point1.y=y-4; point2.x=x+4; point2.y=y+4; LinkLineRedraw(point1,point2); } 此时pNodeNow指向刚擦除小圆圈的元件,而circlepoint则记录着 触点中心。于是只要将以ciclepoint为中心的半径为4的矩形的左上角点和右下角点为参数调用LinkLineRedraw即可。  重绘元件函数redrawMyObject() void CMyView::redrawMyObject(MyNode* pNode) { switch(pNode->Subtype ) { case ANDGate: DrawObject(pNode->Orgpoint ,IDB_ANDGATE); break; case ORGate: DrawObject(pNode->Orgpoint,IDB_ORGATE); break; case NOTGate: DrawObject(pNode->Orgpoint,IDB_NOTGATE); break; case NORGate: DrawObject(pNode->Orgpoint,IDB_NORGATE); break; case NANDGate: DrawObject(pNode->Orgpoint,IDB_NANDGATE); break; case XORGate: DrawObject(pNode->Orgpoint,IDB_XORGATE); break; case Input: DrawObject(pNode->Orgpoint,IDB_NODEINPUT); break; case Output: DrawObject(pNode->Orgpoint,IDB_NODEOUTPUT); break; } } 该函数参数为指向元件的指针,用于重绘所指向的元件。  鼠标按下模块 如图5 图5 前面已经分析了放置元件状态,现在看连接元件状态中的判断: “当前点是否在某个元件未连接的触点上”其实就是判断“可连接态”IsDrawCircle是否为真。代码如下: if(IsDrawCircle)//当前点在某个元件未连接的触点上 { //全局变量IsLink表示开始连接状态 IsLink=TRUE; //全局变量pNodeStart记录当前物件 pNodeStart=pNodeNow; //全局变量startpoint记录当前触点中心坐标(注,此时要进行坐标转换 startpoint.x=pNodeNow->Orgpoint .x +circlepoint.x; startpoint.y=pNodeNow->Orgpoint .y +circlepoint.y; //全局变量startput记录当前触点类别:Input_1,Input_2,Output_1; startput=put; //lastpoint用于鼠标移动时擦除线效果 lastpoint=startpoint; } 进行连接初始化:首先开启开始连接状态 IsLink=TRUE; 然后用全局变量pNodeStart指向当前元件 pNodeStart=pNodeNow 全局变量startpoint记录当前触点中心坐标(这时要进行坐标的转换) startpoint.x=pNodeNow->Orgpoint .x +circlepoint.x; startpoint.y=pNodeNow->Orgpoint .y +circlepoint.y; 全局变量startput记录当前触点类别 startput=put; 最后lastpoint用于鼠标移动时擦除线效果 lastpoint=startpoint;  鼠标抬起模块 其算法如图9 图9 代码如下: void CMyView::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default if(IsLink) { //首先擦除从startpoint到point CClientDC clientDC(this); CClientDC* pDC=&clientDC; CPen whitepen(PS_SOLID,1,RGB(255,255,255)); CPen* pOldPen; pOldPen=clientDC.SelectObject (&whitepen); clientDC.MoveTo (startpoint); clientDC.LineTo (point); clientDC.SelectObject (pOldPen); //重绘所有输入结点前的序号 redrawnum(); //重绘连接线 LinkLineRedraw(startpoint,point); //重绘物件 lineRedraw(startpoint,point); if(IsDrawCircle) { //用全局变量pNodeCurrent记录终点连接的物体 pNodeCurrent=pNodeNow; //用全局变量currentput记录终点连接的触点 currentput=put; //用全局变量currentpoint记录终点触点的中心坐标 currentpoint.x=pNodeNow->Orgpoint .x +circlepoint.x; currentpoint.y=pNodeNow->Orgpoint .y +circlepoint.y; //IsTwoObjectsCanLink()函数判断两个物件是否能连接 if(IsTwoObjectsCanLink()) { //先擦除圆圈 //EraserMyCircle();没有必要,只要鼠标移开时重绘连接线就可 //开始两个物件的画图连接 LineLink(); //开始真正连接:指针连接 RealLink(); } } //关闭连接状态: IsLink=FALSE; } CView::OnLButtonUp(nFlags, point); }  判断两个元件是否可以连接 BOOL CMyView::IsTwoObjectsCanLink() { //判断两个物件是否能连接 //这两个物件分别由pNodeStart和pNodeCurrent指向 //两个触点分别由startput和currentput标识 //若所指同一物件 if(pNodeStart==pNodeCurrent) { MessageBox("连接错误!自身物件不能相互连接"); return FALSE; } //输出直接结输出 if(startput==Output_1 && currentput==Output_1) { MessageBox("连接错误!输出端不能相互连接"); return FALSE; } //输入直接连接输入 if( (startput==Input_1 || startput==Input_2) && (currentput==Input_1||currentput==Input_2) ) { MessageBox("连接错误!输入端不能相互连接"); return FALSE; } //循环连接 if( (startput==Output_1) &&(currentput==Input_1||currentput==Input_2) ) { if(pNodeCurrent->output1 ==pNodeStart) { MessageBox("连接错误!不能循环连接"); return FALSE; } } if( (startput==Input_1||startput==Input_2) &&(currentput==Output_1) ) { if(pNodeStart->output1 ==pNodeCurrent) { MessageBox("连接错误!不能循环连接"); return FALSE; } } //如果以上情况都不发生,表示可以连接 return TRUE; } 用图来表示上述几种错误: 同一元件不能连接 图10 输出端不能连接输出端 图11 输入端不能连接输入端 图12 两个元件不能循环连接 图13  两个元件的画图连接:LineLink() 该函数调用了recordLine() 代码如下: void CMyView::recordLine () { //记录两个物件之间的连接线经过的关键点 //先动态生成一个数组CArray<CPoint,CPoint>之对象 //记录下连接线的关键点,然后将这个数组对象之地址加入到 //CList<CArray<CPoint,CPoint>*,CArray<CPoint,CPoint>*> MyPointList中 int x0,y0,x1,y1,delta_x,delta_y; //(x0,y0)用于记录输出端起始点坐标 //(x1,y1)用于记录输入端终点坐标 //delta_x,delta_y用于记录x和y的偏移量 //一定是从输出端向输入端画线 if(startput==Output_1) { x0=startpoint.x; y0=startpoint.y; x1=currentpoint.x; y1=currentpoint.y; } else { x1=startpoint.x; y1=startpoint.y; x0=currentpoint.x; y0=currentpoint.y; } delta_x=5; //动态生成数组对象 CArray<CPoint,CPoint>* pPointArray=new CArray<CPoint,CPoint>; //根据点的位置分为三种情况:2个点,4个点,5个点 if(x0<x1) { if(y0==y1) { //两个点情况 pPointArray->Add (CPoint(x0,y0)); pPointArray->Add (CPoint(x1,y1)); } else { //4个点情况 pPointArray->Add (CPoint(x0,y0)); pPointArray->Add (CPoint(x0+delta_x,y0)); pPointArray->Add (CPoint(x0+delta_x,y1)); pPointArray->Add (CPoint(x1,y1)); } } else if(x0==x1) { //两个点情况 pPointArray->Add (CPoint(x0,y0)); pPointArray->Add (CPoint(x1,y1)); } else //x0>x1 { //5个点情况 if(y0<y1) { delta_y=20; } else { delta_y=-20; } pPointArray->Add (CPoint(x0,y0)); pPointArray->Add (CPoint(x0,y0+delta_y)); pPointArray->Add (CPoint(x1-delta_x,y0+delta_y)); pPointArray->Add (CPoint(x1-delta_x,y1)); pPointArray->Add (CPoint(x1,y1)); } //加入当前数组对象地址到MyPointList MyPointList.AddTail (pPointArray); //用数组中的点画线 DrawLinkLine(pPointArray); } 首先保证从输出端向输入端画线,这样可以统一画线操作。 然后动态生成数组: CArray<CPoint,CPoint>* pPointArray=new CArray<CPoint,CPoint>; 用指针pPointArray指向该数组,用于存储连接线的关键点。 连接线根据位置总共有三种线型,如下图所示: (1)两个关键点的连接线: 图14 (2)4个关键点的连接线 图15 (3)5个关键点的连接线 图16  两个元件的指针连接:RealLink(); 其代码如下: void CMyView::RealLink() { //一定是输入连接输出 或 输出连接输入 if(startput==Input_1||startput==Input_2) { //输入连接输出 if(startput==Input_1) { pNodeStart->input1 =pNodeCurrent; } else { pNodeStart->input2 =pNodeCurrent; } pNodeCurrent->output1 =pNodeStart; } else//startput==Output_1 { //输出连接输入 pNodeStart->output1 =pNodeCurrent; if(currentput==Input_1) { pNodeCurrent->input1 =pNodeStart; } else { pNodeCurrent->input2 =pNodeStart; } } } 指针连接只有两种情况:输入连接输出和输出连接输入。可以用下图来表示 输入端连接输出端 图17 输出端连接输入端 图18  元件库模块 代码如下: UINT CMyView::gatefunction(MyNode *pNode) { UINT result; switch(pNode->Subtype ) { case ANDGate: result=pNode->input1value & pNode->input2value ; break; case ORGate: result=pNode->input1value | pNode->input2value ; break; case NOTGate: result=pNode->input1value ; result=1-result; break; case NORGate: result=pNode->input1value | pNode->input2value ; result=1-result; break; case NANDGate: result=pNode->input1value & pNode->input2value ; result=1-result; break; case XORGate: result=pNode->input1value ^ pNode->input2value ; } return result; } 这里pNode是指向当前元件的指针,根据当前元件的类型,及当前元件的输入端的值input1value和input2value(注:非门只有一个输入端)来返回元件的输出端的值。 各个门真值表如下表所示: (1)与门 输入端1 输入端2 输出端 0 0 0 0 1 0 1 0 0 1 1 0 表1 (2)或门 输入端1 输入端2 输出端 0 0 0 0 1 1 1 0 1 1 1 1 表2 (3)非门 输入端 输出端 0 1 1 0 表3 (4)与非门 输入端1 输入端2 输出端 0 0 1 0 1 1 1 0 1 1 1 0 表4 (5)或非门 输入端1 输入端2 输出端 0 0 0 0 1 1 1 0 1 1 1 1 表5 (6)异或门 输入端1 输入端2 输出端 0 0 0 0 1 1 1 0 1 1 1 0 表6  计算结果(仿真)模块 仿真模块在整个仿真器中占有最重要的作用。 当在视图窗体上放置元件,连接元件后。接下工具栏开始按钮 开始计算结果,进行仿真。 其主要算法如图19 图19 代码如下: void CMyView::OnBegin() { //开始计算,输出真值表 // TODO: Add your command handler code here //判断是否能够连接 if(CalculateResult()==-1) { MessageBox("连接线路失败!请检查线路"); } else { //可以连接 //调用函数计算 beginCalculate(); //生成对话框对象 CMyDialog MyDialog; MyDialog.DoModal (); } } 其中判断线路是否正确调用了CalculateResult(),这是仿真中最重要的函数。它的返回值是最终输出结点的值。如果返回-1,说明线路有误。其具体的算法如图20: CalculateResult() 图20 代码如下: int CMyView::CalculateResult() { //用于从输入端开始计算输出端结果 //遍历所有输入结点 MyNode* pNode; MyNode* pNodeNext; POSITION pos=MyList.GetHeadPosition (); while(pos!=0) { pNode=MyList.GetNext (pos); //判断当前结点是否是输入结点 if(pNode->Subtype ==Input) { for(;;) { //判断当前的输入结点的输出端指向的结点是否为空 //如果为空,表示连接失败 if(pNode->output1 ==0) { //连接失败,返回-1 return -1; } //否则不为空 //输出到它指向结点的输入端 //此时要判断输入到哪个输入端:input1 OR input2; pNodeNext=pNode->output1 ; if(pNodeNext->input1 ==pNode) { //如果是输入到input1 pNodeNext->input1value =pNode->output1value ; //输入的值++,如果到了2,就可以计算进位了 pNodeNext->inputs ++; } else { //如果是输入到input2 pNodeNext->input2value =pNode->output1value ; pNodeNext->inputs ++; } //指针跳向下一个结点 pNode=pNodeNext; //判断此时是否是输出结点,如果是返回输出结点的值input1value; if(pNode->Subtype ==Output) { return pNode->input1value ; } //判断是否可以进位,对于非门,只要有一个输入值即可inputs==1 //对于其他门,要两个输入值inputs==2 if(pNode->Subtype==NOTGate) { //非门 if(pNode->inputs==1) { //可以进位 pNode->output1value =gatefunction(pNode); } else { //不能进位 break;//跳出for(;;) } } else { //其他门 if(pNode->inputs ==2) { pNode->output1value =gatefunction(pNode); } else { //不能进位 break;//跳出for(;;) } } //请空输入值个数inputs,以便下次计算 pNode->inputs =0; }//for(;;) }//判断当前结点是否是输入结点 }//while(pos!=0) //遍历完后若没有返回,说明连接失败 return -1; } 其算法主要思想是:遍历每一个输入结点,将输入结点的值送入到它所连接的元件的输入端,若此时该元件可以进位,则调用该元件进位函数gatefunction()计算该元件的输出端的值,再将该输出端的值送入它的下一个连接元件,再判断下一个元件能否进位,如此循环,直到输出结点。若此时不可以进位,则遍历下一个输入结点。 可以用下图来说明: 图21 假设此时输入结点遍历的顺序是1->2->3 (顺序不唯一)。假设此时1,2,3号输入结点取值0,1,0。首先将1号输入结点的值送入它所连接的或门的第一个输入端,即input1value=0。此时或门进位标志inputs= =1。于是不能进位。遍历下一个输入结点2,将2号1号输入结点的值送入它所连接的与门的第一个输入端,同样此时与门进位标志也为inputs= =1,不能进位。最后遍历到输入结点3,将值送入到与门的输入端2。由于此时有两个输入了,即与门进位标志inputs= =2,调用与门函数计算与门输出端output1value.然后将此值送入或门,同样或门进位标志inputs= =2,调用或门函数计算或门输出端值,最后送入输出结点,结束。 计算真值表:beginCalculate() 代码如下: void CMyView::beginCalculate() { //计算输入结点的个数,输出真值表 n=numpoint.GetSize (); //计算要进行循环的次数 int i; x=1; for(i=1;i<=n;i++) { x=x*2; } //动态生成x个字符串保存真值表 //用一个字符串格式化数据 CString str; //用一个数组I[1]~I[n]记录每个输入结点值 UINT* I=new UINT[n+1]; //用数组J[1]~J[n]辅助计算 UINT* J=new UINT[n+1]; //初始化J[1]~J[n] J[1]=1; for(i=2;i<=n;i++) { J[i]=J[i-1]*2; } //进行x次循环,计算真值表 for(i=0;i<x;i++) { //增加数组元素:加入一个字符串 strs.Add (CString()); for(int k=1;k<=n;k++) { I[k]=i & J[k]; //向右移位 I[k]=I[k]>>(k-1); //将输入端1~n的值加入字符串 str.Format ("%d ",I[k]); // //连接起来 strs[i]=strs[i]+str; } //给输入结点1~n初始化值 POSITION pos=MyList.GetHeadPosition (); MyNode* pNode; while(pos!=0) { pNode=MyList.GetNext (pos); //如果结点是输入结点 if(pNode->Subtype ==Input) { //结点中的pNode->number 记录了结点序号 //给结点初始化值 pNode->output1value =I[pNode->number ]; } } //调用函数计算,将计算结果保存 int result=CalculateResult(); //生成字符串以便输出 str.Format ("%10d",result); strs[i]+=str; } } 代码分析: (1) 首先得到输入结点的个数:n=numpoint.GetSize (); 这里numpoint是记录输入结点前序号位置点的数组,而有多少个这样的点,就有多少个输入结点。 (2)然后计算真值表的行数,因为有n个输入结点,真值表就有2^n行。 x=1; for(i=1;i<=n;i++) { x=x*2; } 这里我们用x来保存真值表的行数。 (3)产生所有的输入结点值的组合。 如果有3个输入结点,它的所有组合如下表 输入3 输入2 输入1 i 0 0 0 0 0 0 1 1 0 1 0 2 0 1 1 3 1 0 0 4 1 0 1 5 1 1 0 6 1 1 1 7 我们可以从表的第四列看出可以用数字i从0到x-1来分解出这些组合。 例如:当i为2时,它在内存中最后3位为:010。 此时 输入3=010 & 100=000,再右移2位即可得到0。 于是我们可以得到:输入1 & 001 再右移0位 输入2 & 010 再右移1位 输入1 & 100 再右移2位 我们用一个数组J[1]~J[n]来记录相与的数字。为1,2,4,......,2^(n-1) 初始化J[1]~J[n] J[1]=1; for(i=2;i<=n;i++) { J[i]=J[i-1]*2; } 用I[1]~I[n]记录输入1~输入n 产生一行输入值: strs.Add (CString()); for(int k=1;k<=n;k++) { I[k]=i & J[k]; //向右移位 I[k]=I[k]>>(k-1); //将输入端1~n的值加入字符串 str.Format ("%d ",I[k]); // //连接起来 strs[i]=strs[i]+str; } 给输入结点1~n初始化值 POSITION pos=MyList.GetHeadPosition (); MyNode* pNode; while(pos!=0) { pNode=MyList.GetNext (pos); //如果结点是输入结点 if(pNode->Subtype ==Input) { //结点中的pNode->number 记录了结点序号 //给结点初始化值 pNode->output1value =I[pNode->number ]; } } 调用函数计算,将计算结果保存 int result=CalculateResult(); 最后生成字符串以便输出 str.Format ("%10d",result); strs[i]+=str; 完成以上操作后,生成一个对话框,然后将字符串数组strs[]加入到列表框内。最终输出整个真值表。 参考文献: 1 Electronics Workbench 5.0 1992-1996 Interactive Image Technologies Ltd 2 MSDN Libary July 2000 Microsoft

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值