關於題目集7~8的總結

违规名称6發表於2024-06-28

前言
第七次大作業和第八次大作業都是關於家居強電電路模擬程式的模擬和實現,題目綜合性強資訊多,每次迭代在前一次的基礎上增加一到兩個新的電路元件和增強電路的複雜性,需要綜合考慮新的電路情況與前面的電路元件進行結合,電路的連線情況較為複雜,需要考慮多種特殊情況和某些電路元件來凝結的特殊性。這些在做專案需求分析時要考慮務必詳細。這兩次的題目集難度相比較大,主要在於不同的電路元件處理方式的差異和電路的各種異常如出現短路或斷路對某些元件的特殊影響需要單獨考慮。

第七次大作業

本次大作業新增了新的電路元件互斥開關和窗簾,且互斥開關為避免出現短路現象給不同的擋位設定了不同電阻,每個受控裝置都具有各自的電阻,窗簾元件受到電路電壓和電路光照強度的雙重影響,因此在電路中存在窗簾時要單獨考慮電路中是否有白熾燈或日光燈並求出總的光照強度。電路資訊由一條連線資訊佔一行,用[]表示一組連線在一起的裝置引腳給出,因此要用正規表示式讀取給定的電路資訊,互斥開關較為特殊,當互斥開關兩端都給出時是以並聯形式給出的,但實際上是串聯電路,但也可以根據需要只取一邊,不論是否連通,在設定帶你路時要額外考慮。

設計分析

在設計電路將Device類作為所有裝置類的父類,為方便同意處理,將串聯類和並聯類都看成是Device的一個子類,由於題目允許將一條串聯電路視為一個裝置給出,則在讀到串聯電路時將該串聯電路中的所有裝置組成list集合返回,由於互斥開關有三個引腳,既可以13引腳連線也可以23引腳連線,在預設情況下是13引腳兩聯,本次題目考慮多個並聯電路串聯在一起的情況,因此每個並聯電路要有自己的處理方法,包括考慮短路和斷路等異常情況。
相關原始碼解析:

 if(str0.startsWith("H")){
            String[] s = str0.split("-");
            MuxSwitch muxSwitch = new MuxSwitch();
            muxSwitch.name = s[0];
            if(!MuxSwitchCount.containsKey(muxSwitch.name)){
                //如果不存在就把value設定為1
                if(!s[1].equals("1"))
                    MuxSwitchCount.put(muxSwitch.name,1);
            }else{
                //如果存在就value+1
                if(!s[1].equals("1"))
                    MuxSwitchCount.put(muxSwitch.name,MuxSwitchCount.get(muxSwitch.name)+1);
            }
            boolean exit = false;
            for(int i=0;i<devices.size();i++){
                if(devices.get(i).name.equals(muxSwitch.name)){
                    exit = true;
                    break;
                }
            }
            if (!exit) {
                devices.add(muxSwitch);
                if (s[1].equals("2")) {
                    muxSwitch.Pin = 2;
                }else if(s[1].equals("3"))
                    muxSwitch.Pin = 3;
            }
        }

在讀入互斥開關資訊之前,建立了一個map轉麼用來儲存互斥開關的名字和數量,如果互斥開關的數量為1說明該互斥開關使用了其中一邊,如果當互斥開關的數量為2則說明該互斥開關的兩邊都要在電路中考慮,電路只會透過一邊。

之所以互斥開關要這樣處理是因為互斥開關給出的方式可能有變化,當給出一個map中某互斥開關的數量為2時,題目是以並聯的形式給出的,但實際上互斥開關只有1引腳或2引腳才能與2引腳相接,電路也只會走一邊,明顯這其實是一個串聯電路,互斥開結束通話開的一段上的所有裝置都不應包含在電路中,但是最後仍要輸出,因此在最後再把電路中沒有的元件即沒有電流透過的裝置加入主串聯電路中。
而當互斥開關的數量為1時說明電路中只給出了互斥開關某一邊的資訊,而未給出的則不用考慮,但是再給出的一段並不一定是互斥開關連通的一端而有可能是斷開的一段,那麼相當於斷路,但是當互斥開關是以並聯形式給出時並不一定說明互斥開關再map中的數量為2,可能這就是一個並聯電路但是兩條支路上各有一個互斥開關,而各個互斥開關給出的是連通的資訊還是不連通的資訊要根據互斥開關引腳連線情況和互斥開關切換開關的情況,情況較為複雜,再互斥開關元件上要額外判斷互斥開關的確切情況。

注意:互斥開關是一個難點,要考慮的情況較複雜。普通開關是沒有電阻的,而互斥開關無論哪條路都有電阻,但是互斥開關單獨連在裝置或某段電路上仍會導致短路現象,還有考慮串聯支路上有多個互斥開關和普通開關串聯導致該串聯支路短路或斷路的情況,因此互斥開關根據給出的情況不同處理的方式也有所不同。

    for(int k=0;k< parallels.size();k++) {
            Parallel parallel = parallels.get(k);
            for (int i = 0; i < parallel.list.size(); i++) {
                Contact contact = parallel.list.get(i);
                for (int j = 0; j < contact.devices.size(); j++) {
                    Device device = contact.devices.get(j);
                    if(device instanceof MuxSwitch&&MuxSwitchCount.get(device.name)==2){
                        for(int n=0;n< contact.devices.size();n++)
                            contact.devices.get(n).direct=0;
                        break;
                    }else{
                        device.direct = 1;
                    }
                }
            }
        }

這裡將串聯電路上的裝置和並聯電路上的設別加以區分,當裝置是在串聯電路上時direct設為0,當裝置是在並聯電路上時direct設為1,但由於互斥開關在map中的值為2時是以並聯方式給出的但是實際上這是一條串聯電路,因此將與該互斥開關相連的所有裝置的direct全部設定為0.

 public void ParallelJudgement() {   
        for(int i=0;i<list.size();i++){
            Contact contact = list.get(i);
            int count=0;
            for(int j=0;j<contact.devices.size();j++){
                Device device = contact.devices.get(j);
                if(device instanceof Switcher&&((Switcher)device).flag==1)
                    count++;
                if(device instanceof MuxSwitch&&((MuxSwitch)device).isUseful()%10!=0) {
                    count++;
                }
            }
            if(count==contact.devices.size()){
                //這條路短路
                this.isShort = true;
                contact.flag = true;
                for(int j=0;j< list.size();j++){
                    Contact contact1 = list.get(j);
                    if(!contact1.flag){
                        for(int k=0;k<contact1.devices.size();k++)
                            contact1.devices.get(k).useful = false;
                    }
                }
            }
            for(int j=0;j<contact.devices.size();j++){
                Device device = contact.devices.get(j);
                if(device instanceof Switcher&&((Switcher)device).flag==0){
                    for(int k=0;k<contact.devices.size();k++){
                        contact.devices.get(k).useful = false;
                    }
                }
                if(device instanceof MuxSwitch&&((MuxSwitch)device).isUseful()%10==0){
                    for(int k=0;k<contact.devices.size();k++){
                        contact.devices.get(k).useful = false;
                    }
                }
            }
        }

    }

當讀到並聯電路時呼叫該方法處理,主要目的是判斷該並聯是否短路和斷路,當出現短路情況時將被短路的所有串聯支路上的所有裝置的useful屬性改為false,意思是該裝置實際上沒有電流透過,或者當出現斷路現象時,將該斷路支路上的所有裝置的useful屬性改為false。如果並聯電路中所有支路全部斷開,則該並聯電路無效,直接將總電壓變0.

 //計算電路總電阻
        double TotalResist = 0;
        for (int i = 0; i < contacts.get(contacts.size() - 1).devices.size(); i++) {
            Device device = contacts.get(contacts.size() - 1).devices.get(i);
            if (device.getTypeValue() <= 10)
                TotalResist += device.getResist();
            else if (device.getTypeValue() == 100) {
                Parallel parallel = (Parallel) device;
                //沒出現短路
                if(!parallel.isShort){
                    int count=0,useful=0;
                    for(int j=0;j<parallel.list.size();j++){
                        Contact contact = parallel.list.get(j);
                        for(int k=0;k<contact.devices.size();k++){
                            Device device1 = contact.devices.get(k);
                            if(device1 instanceof MuxSwitch){
                                count++;
                                if(((MuxSwitch) device1).isUseful()==21||((MuxSwitch) device1).isUseful()==31)
                                    useful++;
                                break;
                            }
                        }
                    }
                    if(useful==1)
                        TotalResist+= parallel.getSwitchResist();
                    else
                        TotalResist+= parallel.getResist();
                }else{
                    //這條並聯短路
                    for(int j=0;j<parallel.list.size();j++){
                        Contact contact = parallel.list.get(j);
                        if(contact.flag){
                            for(int k=0;k<contact.devices.size();k++)
                                TotalResist+=contact.devices.get(k).getResist();
                        }
                    }
                }
            } else if (device.getTypeValue() == 50) {
                for (int j = 0; j < contacts.size(); j++) {
                    if (contacts.get(j).name.equals(device.getName())) {
                        List<Device> list2 = contacts.get(j).devices;
                        for (int k = 0; k < list2.size(); k++) {
                            TotalResist += list2.get(k).getResist();
                        }
                    }
                }
            }
        }

這裡計算電路的總電阻,當遇到並聯電路時先判斷是否短路,如果出現短路從並聯的所有支路中找到有效的支路遍歷所有裝置求電阻,在如果並聯正常,就用物理方式求解電路的總電阻,之後開始給每個有效的裝置分壓,當遇到串聯的裝置,直接用比例賦電壓,如果是並聯,就呼叫並聯的求電壓方法,為並聯的每個裝置分壓,並聯分壓方法程式碼如下:

if (device.direct==1 ) {
                Parallel parallel = null;
                for(int j=0;j<parallels.size();j++){
                    Parallel parallel1 = parallels.get(j);
                    for(int k=0;k<parallel1.list.size();k++){
                        Contact contact = parallel1.list.get(k);
                        for(int n = 0;n<contact.devices.size();n++){
                            Device device1 = contact.devices.get(n);
                            if(device1.getName().equals(device.getName())){
                                parallel = parallel1;
                            }
                        }
                    }
                }
                double parallelValue =  (parallel.getResist()/TotalResist)*Function.value;  //整個並聯電路的分壓
                device.value = parallel.getRate(device)*parallelValue;
            }

最後將電路總串聯上沒有的裝置加入,最後呼叫每個裝置的列印方法輸出。

相關類圖

踩坑分析

這裡易錯的地方有以下幾點:
1.對互斥開關的理解,互斥開關雖然是以並聯方式給出且有三個引腳,但是隻有兩個引腳相連因此看成是一條串聯電路,這裡對該互斥開關哪條支路連進電路中要判斷準確,其次,互斥開關初始狀態是引腳1和引腳3相連,但是透過切換開關狀態的方式使引腳2與引腳3相連,要根據兩方面綜合考慮。
2.互斥開關也可能是以串聯方式給出,可以是一個互斥開關以串聯方式出現,也可以是多個互斥開關以並聯方式出現,兩種情況處理起來不相同,要區分開來處理
3.窗簾處理的時候既要考慮電壓也要考慮光照,由於只考慮電路中裝置的光照,因此在窗簾的輸入方法中要統計電路中的光照強度大小

這裡最重要也是最難的就是互斥開關的處理,由於互斥開關變化多樣,我一開始沒有想到互斥開關可以以串聯形式單連線一邊,以為互斥開關只能以並聯形式出現導致電路設計不全面最後不得不將程式碼全部重新設計。這裡也提醒了在做需求分析時務必要做到全面,嚴謹。

改進建議

在計算電路電阻時考慮不周,將有互斥開關的並聯電路和沒有互斥開關的電聯電路的電阻分來來用兩個方法計算,這樣實際上對互斥開關真實並聯的情況的電阻沒有考慮,計算邏輯也很麻煩,應該將兩個方法合一或者將沒有互斥開關的電路在前面就處理,後面處理起來就簡便。

第八次大作業

前言
第八次大作業是在第七次作業的基礎上進一步提高要求,要求在輸入每個裝置的資訊後輸出每個裝置兩個引腳的電壓,並且考慮電流過大問題,每個裝置都設定了一個最大電流,當經過裝置電流超過最大電流時,輸出 exceeding current limit error。本次題目考慮在並聯電路的串聯電路中存在並聯電路,存在巢狀關係。且新增元件二極體,當正方向放入電路中電阻為0,當反方向放入電路中時電阻無窮大

設計分析

    public void ParallelJudgement() {
        for(int i=0;i<list.size();i++){
            Contact contact = list.get(i);
            int count=0;
            for(int j=0;j<contact.devices.size();j++){
                Device device = contact.devices.get(j);
                if(device instanceof Parallel){
                    ((Parallel) device).ParallelJudgement();
                    if(((Parallel) device).isUseful()==false){
                        for(int n=0;n<contact.devices.size();n++)
                            contact.devices.get(n).useful = false;
                    }
                }
                if(device instanceof Switcher&&((Switcher)device).flag==1)
                    count++;
                if(device instanceof MuxSwitch&&((MuxSwitch)device).isUseful()%10!=0) {
                    count++;
                }
                if(device instanceof  Parallel&&((Parallel)device).isShort)
                    count++;
            }
            if(count==contact.devices.size()){
                //這條路短路
                this.isShort = true;
                contact.flag = true;
               for(int j=0;j< list.size();j++){
                   Contact contact1 = list.get(j);
                   if(!contact1.flag){
                         for(int k=0;k<contact1.devices.size();k++)
                               contact1.devices.get(k).useful = false;
                   }
               }
            }
            for(int j=0;j<contact.devices.size();j++){
                Device device = contact.devices.get(j);
                if(device instanceof Switcher&&((Switcher)device).flag==0){
                    for(int k=0;k<contact.devices.size();k++){
                        contact.devices.get(k).useful = false;
                    }
                }
                if(device instanceof MuxSwitch&&((MuxSwitch)device).isUseful()%10==0){
                    for(int k=0;k<contact.devices.size();k++){
                        contact.devices.get(k).useful = false;
                    }
                }
                if(device instanceof Diode&& !((Diode) device).direction){
                    for(int k=0;k<contact.devices.size();k++){
                        contact.devices.get(k).useful = false;
                    }
                }
            }
        }

    }

當遇到二極體且方向為正時相當於導線,在考慮短路情況時要考慮,當方向為反時,該支路斷路,該支路上所有裝置全部設為無效,其他部分與上次大作業基本上相同。

 public void setCircuit(double paraValue){     //給並聯分流
       for(int i=0;i<list.size();i++){
           Contact contact = list.get(i);
           double total = 0;
           for(int j=0;j<contact.devices.size();j++){
               Device device = contact.devices.get(j);
               total+=device.getResist();
           }

           for(int j=0;j<contact.devices.size();j++){
               Device device = contact.devices.get(j);
               if(device.useful) {
                   if (device instanceof Parallel) {
                       Parallel parallel = (Parallel) device;
                       parallel.setCircuit(device.value);
                   } else {
                       if(total!=0)
                            device.Electricity = paraValue / total;
                   }
               }
           }
       }
   }

這裡是給並聯電路的每個裝置分配電流,由於可能存在串聯支路上有並聯電路的情況,因此計算電流要一直計算到最裡層的串聯支路的電流,因為外層的電流等於裡層支路電流之和,要確保每個裝置都準確分配了各自的電流。

 for (int i = 0; i < contacts.get(contacts.size() - 1).devices.size(); i++){
            Device device = contacts.get(contacts.size() - 1).devices.get(i);
            if(device.getTypeValue()<20){   //普通裝置
                device.pin1Value = v;
                v-=device.value;
                device.pin2Value = v;
            }
            else if(device.getTypeValue()==100){   //並聯
                Parallel parallel = (Parallel)device;
                double[] values = new double[parallel.list.size()];
                for(int j=0;j<parallel.list.size();j++){
                    values[j] = Function.v;
                }

                for(int j=0;j<parallel.list.size();j++){
                    Contact contact = parallel.list.get(j);
                    if(!contact.hasParallel()){   //正常的串聯支路
                        for(int k=0;k<contact.devices.size();k++){
                            Device device1 = contact.devices.get(k);
                            device1.pin1Value = values[j];
                            values[j]-=device1.value;
                            device1.pin2Value = values[j];
                        }
                        }else{   //並聯的串聯支路中存在並聯
                            for(int k=0;k<contact.devices.size();k++){
                                Device device1 = contact.devices.get(k);
                                if(device1.getTypeValue()<20){
                                    device1.pin1Value = values[j];
                                    values[j]-=device1.value;
                                    if(contact.devices.get(k+1)!=null&&contact.devices.get(k+1).useful)
                                        device1.pin2Value = values[j];
                                }else if(device1.getTypeValue()==100){    //遇到並聯電路
                                    Parallel parallel1 = (Parallel)device1;
                                    parallel1.setPinValue();
                                }
                        }
                    }
                }
            }
        }

這裡給裝置兩個引腳賦電壓值,從總電壓開始,每次遇到裝置分壓都用總電壓減去裝置分壓值,遇到並聯電路時則每條串聯支路的電壓都相同,急促依次為每個引腳賦電壓值,這裡要注意互斥開關,要考慮清楚互斥開關是那兩個開關接通,一定有一個引腳的電壓為0.

踩坑心得

做需求分析和實現程式碼時要注意以下幾點:

1.電路中存在互斥開關,二極體等特殊元件,可能會導致電路出現斷路和短路的情況出現,在判斷電路的異常情況時要多注意這些元件
2.計算電流時要考慮串聯中巢狀並聯的情況,一開始在設計的時候為每個裝置分壓,以為裝置的電流就直接用電壓除設別的電阻,實際上這種想法是錯誤的,比如開關,不分壓且沒有電阻,無法透過這種方式計算透過開關的電流,如果存在巢狀並聯的情況,那麼串聯的電流等於巢狀並聯的總電流
3.在為設別兩端分壓時要注意,當電流經過某裝置時在後面斷開了,那麼該裝置前面的引腳有電壓而後面的引腳電壓為0,不能僅僅考慮裝置分壓的情況,還要綜合考慮各種其他的情況

改進意見

在計算電流的方法上存在問題,如果在一條串聯電路上有巢狀並聯且有多個的情況下,最好能遞迴處理,完全靠邏輯去處理太複雜而且情況考慮不全面,在計算裝置兩端引腳的分壓時也有錯誤,如果設別前面或者後面斷開時裝置的引腳電壓是不相同的

兩次作業的大總結

1.這類題目經過多次迭代難度大大增強尤其是最後一次,電路設計都十分苦難,有各種特殊情況不知道怎麼去考慮,在前面的題目出現問題沒有解決那麼後面問題一尺存在且不一定能被發現
2.提示點太籠統不知道什麼情況才是測試點,有時候改對了很多測試用例但是都不是題目要求的測試點,題目給的測試點不具有代表性
3.大作業一直只是做,如果有沒有思路的很難動筆,別人的也很難看懂,導致這次以及以後的迭代都很難產生思路,我認為老師要適當的講解和提示。