Matlab – luogo delle radici – PGF & TikZ

  • Creatore
    Topic
  • #65271
    tonegas
    Partecipante
      Up
      0
      Down
      ::


      Qualcuno mi sa illustrare i passaggi per generare un grafico utilizzando PGF e TikZ contenente un luogo delle radici?
      Premesse:

      • – so utilizzare PGF e TikZ per generare grafici recuperando i vettori numerici da file;
      • – so utilizzare Matlab per generare un luogo delle radici.

      Ma non so fare e vorrei capire se è possibile:

      • – salvare il grafico di matlab in un formato a vettori, essendo il luogo delle radici di fatto una funzione parametrica, o in un qualsiasi altro formato che possa essere letto da PGF e TikZ;
      • – non so creare un grafico parametrico con PGF e TikZ.

      Grazie anticipato a chiunque mi dedichi attenzione.
      Gastone

    Visualizzazione 10 filoni di risposte
    • Autore
      Risposte
      • #65272
        Up
        0
        Down
        ::


        Comincia a vedere la presentazione_Pgfplots_GuITmeeting_2011.pdf, pagina 10.
        Poi ti consiglio caldamente di studiare il manuale di pgfplots: pgfplots.pdf.
        Quello che ti interessa è a pagina 25-26.

        Ciao,
        Agostino

      • #65273
        Liverpool
        Partecipante
          Up
          0
          Down
          ::

          tonegas” post=64295

        • – salvare il grafico di matlab in un formato a vettori, essendo il luogo delle radici di fatto una funzione parametrica, o in un qualsiasi altro formato che possa essere letto da PGF e TikZ;
        • Matlab genera un vettore di numeri complessi per ogni ramo del luogo e disegna ogni elemento dei singoli vettori come punto sul piano di Gauss con un colore differente, partendo dai poli; quindi, di fatto, non si tratta di un grafico parametrico, ma di N grafici cartesiani sovrapposti. Per conoscere i punti del luogo, devi usare il comando

          `r = rlocus(h);`

          Ogni riga corrisponde ad un ramo differente e ogni elemento complesso della riga corrisponde ad una coppia ordinata sul piano di Gauss.
          Quando scrivi su file, devi separare le parti reali da quelle immaginarie e incolonnare i valori. Questo è il punto di partenza. Se ti servono ulteriori indicazioni possiamo provare ad andare avanti insieme.

          Per pgfplot però mi tiro indietro, non avendo mai provato.

          Ciao

        • #65274
          Up
          0
          Down
          ::


          Se riesci ad ottenere il grafico su matlab ti basta utilizzare matlab2tikz. Certo, si può anche utilizzare pgfplots, ma matlab2tikz è decisamente più veloce (ovviamente ammesso che tu abbia il grafico matlab).

        • #65275
          tonegas
          Partecipante
            Up
            0
            Down
            ::


            Lavorando ci un po’ su posso spiegare i passaggi iniziali.
            Il grafico che ottengo però non è molto bello.
            Se qualcuno trovasse dei modi per migliorarlo è bene accetto.

            Allora su matlab:
            `
            [r,k] = rlocus(FDT);
            r_re_im= [real(r)',imag(r)',k'];
            save('dati.mat','-ascii','r_re_im');
            `

            Invece per creare il pdf con il grafico con pgfplots:

            `
            \documentclass[landscape,a5paper,11pt]{article}
            \usepackage[utf8x]{inputenc} % utf8 encoding

            \usepackage{color} % change text color

            \usepackage{tikz}
            \usepackage{pgfplots}
            \usepackage{pgfplotstable}

            \usepackage[active,tightpage]{preview}
            \PreviewEnvironment{tikzpicture}
            \setlength\PreviewBorder{0pt}

            \usetikzlibrary{plotmarks}

            %nome del file
            \newcommand{\name}{dati.mat}

            %inserire il numero di righe
            \newcommand{\righenum}{17}

            \begin{document}
            \begin{tikzpicture}
            \begin{axis}[ymin=-150,ymax=150,xmin=-19,xmax=2,xmajorgrids,ymajorgrids,xtick={0},ytick={0}]
            %qui bisogna inserire tutte le colonne a gruppi reale immaginario
            %in questo caso il grafico ha 4 poli
            \foreach \re / \im in {0/4,1/5,2/6,3/7}{
            \pgfplotstablegetelem{0}{\re}\of{\name}
            \let\varpr = \pgfplotsretval
            \pgfplotstablegetelem{0}{\im}\of{\name}
            \let\varpi = \pgfplotsretval
            \addplot[mark = x] coordinates {(\varpr,\varpi)};

            \pgfplotstablegetelem{\righenum}{\re}\of{\name}
            \let\varzr = \pgfplotsretval
            \pgfplotstablegetelem{\righenum}{\im}\of{\name}
            \let\varzi = \pgfplotsretval
            \addplot[mark = o] coordinates {(\varzr,\varzi)};
            \addplot[no marks] table[x index = \re, y index = \im]{\name};
            }
            \end{axis}
            \end{tikzpicture}
            \end{document}
            `

            Ci sono vari abbellimenti che possono essere fatti al grafico.
            – In più sarebbe bello che capisse in automatico il numero di campioni totale così da inserire gli zeri nel grafico.
            – sarebbe bello si riuscisse a fare in automatico le coppie [numero reale, numero immaginario] indipendentemente dal numero di poli.

            Grazie a tutti per i consigli.
            Gastone

          • #65276
            Liverpool
            Partecipante
              Up
              0
              Down
              ::


              Premessa: penso che Claudio (cfiandra) ti abbia dato un consiglio d’oro. Potresti generare il codice TikZ e poi modificare quello.

              tonegas” post=64389– In più sarebbe bello che capisse in automatico il numero di campioni totale così da inserire gli zeri nel grafico.

              Comando \pgfplotstablegetrowsof a pag. 56 del manuale di pgfplotstable. Un esempio che ti può essere utile, lo trovi qui.

              tonegas” post=64389– sarebbe bello si riuscisse a fare in automatico le coppie [numero reale, numero immaginario] indipendentemente dal numero di poli.

              Con \pgfplotstablegetcolsof, sempre a pag. 56 del manuale di pgfplotstable, puoi conoscere il numero di colonne. Utilizzando \foreach e i puntini di sospensione, puoi andare da 0 ad (ncol – 1) / 2 – 1 per le parti reali e da (ncol – 1) / 2 ad (ncol – 1) per le parti immaginarie. Il -1 tra parentesi serve perché l’ultima colonna riporta i valori di k che non ci interessano (e non ho capito perché li hai salvati).

              Cosiderazioni su Matlab.
              Tieni presente che, se ci sono zeri all’infinito, Matlab ti darà degli Inf tra i valori numerici e non so come verrebbero trattati da pgfplots. Se dovessero dare problemi, la soluzione potrebbe essere di sostituirli con dei nan che pgfplots ignorerebbe.
              Non mi fido troppo del metodo con il quale Matlab individua i rami del luogo. Penso che Mathematica sia più affidabile.
              Dal punto di vista dell’interpretazione dei dati, sarebbe meglio se le coppie parte reale/immaginaria si trovassero in colonne adiacenti. Un codice per ottenerlo potrebbe essere:

              `
              [nrow, ncol] = size(r);
              r_re_im = [real(r) imag(r)]';
              r_re_im = [reshape(r_re_im, ncol, 2*nrow) k'];`
              corrispondente al più sintetico:

              `
              r_re_im = [reshape([real(r) imag(r)]', size(r, 2), 2*size(r, 1)) k'];`
              Ovviamente poi dovresti riscrivere il codice del \foreach prendendo le colonne pari a partire da 0 per le parti reali e quelle dispari per le parti immaginarie.

              Ciao

            • #65277
              tonegas
              Partecipante
                Up
                0
                Down
                ::


                Ho modificato il codice che crea l’immagine con le due nuove features :

                – In più sarebbe bello che capisse in automatico il numero di campioni totale così da inserire gli zeri nel grafico.
                – sarebbe bello si riuscisse a fare in automatico le coppie [numero reale, numero immaginario] indipendentemente dal numero di poli.

                `
                \documentclass[landscape,a5paper,11pt]{article}
                \usepackage[utf8x]{inputenc} % utf8 encoding

                \usepackage{color} % change text color

                \usepackage{tikz}
                \usepackage{pgfplots}
                \usepackage{pgfplotstable}

                \usepackage[active,tightpage]{preview}
                \PreviewEnvironment{tikzpicture}
                \setlength\PreviewBorder{0pt}

                \usetikzlibrary{plotmarks}

                %nome del file
                \newcommand{\name}{dati.mat}

                \begin{document}
                \begin{tikzpicture}
                \pgfplotstableread[header=true]{\name}{\datawhead}
                \pgfplotstableread[header=false]{\name}{\data}
                \pgfplotstablegetrowsof{\datawhead}
                \pgfmathsetmacro{\rows}{\pgfplotsretval}
                \pgfplotstablegetcolsof{\data}
                \pgfmathsetmacro{\cols}{\pgfplotsretval}

                \pgfmathsetmacro{\goodrows}{\rows-2}
                \pgfmathsetmacro{\goodcols}{(\cols-1)/2-1}

                \begin{axis}[ymin=-150,ymax=150,xmin=-19,xmax=2,xmajorgrids,ymajorgrids,xtick={0},ytick={0}]
                \foreach \re in {0,1,…,\goodcols}{

                \pgfmathparse{int(\re + 4)}\let\im=\pgfmathresult

                \pgfplotstablegetelem{0}{\re}\of\datawhead
                \let\varpr = \pgfplotsretval
                \pgfplotstablegetelem{0}{\im}\of\datawhead
                \let\varpi = \pgfplotsretval
                \addplot[mark = x] coordinates {(\varpr,\varpi)};

                \pgfplotstablegetelem{\goodrows}{\re}\of\datawhead
                \let\varzr = \pgfplotsretval
                \pgfplotstablegetelem{\goodrows}{\im}\of\datawhead
                \let\varzi = \pgfplotsretval
                \addplot[mark = o] coordinates {(\varzr,\varzi)};
                \addplot[no marks] table[x index = \re, y index = \im]{\name};
                }
                \end{axis}
                \end{tikzpicture}
                \end{document}
                `

                Ora una cosa che mi chiedevo è se era possibile rendere il grafico un po’ smooth.
                Ho provato ma il risultato è pessimo (la funzione non segue assolutamente l’andamento corretto);
                mi chiedevo se esistevano diverse tipologie di smooth magari che utilizzano algoritmi diversi per unire i punti nel grafico oppure se esistevano comandi differenti per questo scopo.
                Il resto va bene il grafico risulta però un po’ povero e quindi non molto gradevole chi avesse delle idee per completarlo sono beneaccette.
                Di seguito inserisco anche dei dati di prova per testare il codice.

                `
                0.0000000e+000 -1.6083257e+001 -1.6083257e+001 -5.3334869e+000 0.0000000e+000 6.5534488e+001 -6.5534488e+001 0.0000000e+000 0.0000000e+000
                -1.0387366e-001 -1.6083215e+001 -1.6083215e+001 -5.2296956e+000 0.0000000e+000 6.5538109e+001 -6.5538109e+001 0.0000000e+000 8.1490264e+000
                -3.1745913e-001 -1.6083135e+001 -1.6083135e+001 -5.0162712e+000 0.0000000e+000 6.5545105e+001 -6.5545105e+001 0.0000000e+000 2.3893509e+001
                -1.1028158e+000 -1.6082891e+001 -1.6082891e+001 -4.2314017e+000 0.0000000e+000 6.5565632e+001 -6.5565632e+001 0.0000000e+000 7.0057418e+001
                -2.5830389e+000 -1.6082690e+001 -1.6082690e+001 -2.7515817e+000 0.0000000e+000 6.5581962e+001 -6.5581962e+001 0.0000000e+000 1.0675388e+002
                -2.6673108e+000 -1.6082689e+001 -1.6082689e+001 -2.6673110e+000 0.0000000e+000 6.5582010e+001 -6.5582010e+001 0.0000000e+000 1.0686074e+002
                -2.6673115e+000 -1.6082688e+001 -1.6082688e+001 -2.6673115e+000 -8.4271264e-002 6.5582058e+001 -6.5582058e+001 8.4271264e-002 1.0696760e+002
                -2.6678868e+000 -1.6082113e+001 -1.6082113e+001 -2.6678868e+000 -2.5575616e+000 6.5625929e+001 -6.5625929e+001 2.5575616e+000 2.0541319e+002
                -2.6707166e+000 -1.6079283e+001 -1.6079283e+001 -2.6707166e+000 -5.7194884e+000 6.5803680e+001 -6.5803680e+001 5.7194884e+000 6.0228567e+002
                -2.6837242e+000 -1.6066276e+001 -1.6066276e+001 -2.6837242e+000 -1.0386681e+001 6.6332966e+001 -6.6332966e+001 1.0386681e+001 1.7659432e+003
                -2.7617205e+000 -1.5988279e+001 -1.5988279e+001 -2.7617205e+000 -1.7746353e+001 6.7951656e+001 -6.7951656e+001 1.7746353e+001 5.1778675e+003
                -3.2851406e+000 -1.5464859e+001 -1.5464859e+001 -3.2851406e+000 -2.8509726e+001 7.3189874e+001 -7.3189874e+001 2.8509726e+001 1.5181865e+004
                -5.5465705e+000 -1.3203430e+001 -1.3203430e+001 -5.5465705e+000 -3.9760466e+001 9.0611038e+001 -9.0611038e+001 3.9760466e+001 4.4514279e+004
                -6.1863124e+000 -1.2563688e+001 -1.2563688e+001 -6.1863124e+000 -4.1412378e+001 9.7010898e+001 -9.7010898e+001 4.1412378e+001 5.5264861e+004
                -6.6944716e+000 -1.2055528e+001 -1.2055528e+001 -6.6944716e+000 -4.2556842e+001 1.0321275e+002 -1.0321275e+002 4.2556842e+001 6.6015444e+004
                -7.4211868e+000 -1.1328813e+001 -1.1328813e+001 -7.4211868e+000 -4.4012190e+001 1.1492517e+002 -1.1492517e+002 4.4012190e+001 8.7516610e+004
                -8.2357836e+000 -1.0514216e+001 -1.0514216e+001 -8.2357836e+000 -4.5465781e+001 1.3582335e+002 -1.3582335e+002 4.5465781e+001 1.3051894e+005
                -9.9961508e+000 -8.7538492e+000 -8.7538492e+000 -9.9961508e+000 -4.8249472e+001 2.7249372e+003 -2.7249372e+003 4.8249472e+001 5.9387299e+007
                -1.0000000e+001 Inf Inf -1.0000000e+001 -4.8255274e+001 0.0000000e+000 0.0000000e+000 4.8255274e+001 Inf
                `

                Gastone

              • #65278
                Up
                0
                Down
                ::

                Ora una cosa che mi chiedevo è se era possibile rendere il grafico un po’ smooth.
                Ho provato ma il risultato è pessimo (la funzione non segue assolutamente l’andamento corretto);
                mi chiedevo se esistevano diverse tipologie di smooth magari che utilizzano algoritmi diversi per unire i punti nel grafico oppure se esistevano comandi differenti per questo scopo.

                Questi problemi andrebbero risolti a monte. Non è il caso di chiedere a pgfplots di fare anche lo smoothing. Se usi Matlab ci sono le cubic smoothing spline. Se hai N punti per ciascun luogo delle radici, puoi ottenere una smoothing spline in Matlab con csaps e valutarla, ad esempio, in 3N punti e scriverli su file. Se vuoi puoi approfondire qui (pagina 15).

                Agostino

              • #65279
                Liverpool
                Partecipante
                  Up
                  0
                  Down
                  ::

                  tonegas” post=64432Ora una cosa che mi chiedevo è se era possibile rendere il grafico un po’ smooth.

                  Anch’io ti consiglio di lavorare sui dati di Matlab, ma ti sconsiglio di usare l’interpolazione cubica perché i due rami di destra hanno un punto angoloso e la spline potrebbe non essere adatta.
                  Invece, potresti aumentare il numero di punti del grafico semplicemente imponendo tu i valori di guadagno in corrispondenza dei quali determinare la posizione dei poli in anello chiuso con il comando:
                  `
                  r = rlocus(FDT, k);
                  `
                  dove k, nel tuo caso, è un vettore con più di 17 elementi, ovviamente. Il problema è come scegliere i valori di k senza risparmiare (perché potresti ottenere un grafico che non corrisponde alla realtà) o senza esagerare (perché ti troveresti tanti punti inutili magari dove non servono, ad esempio in un segmento). Siccome Matlab non li sceglie a casaccio, una soluzione potrebbe essere:
                  1) fai una prima chiamata [r, k] = rlocus(FDT); e ti determini automaticamente i valori di k di partenza;
                  2) a partire da questi, ti costruisci un nuovo vettore k nel quale, tra ogni coppia di elementi di quello di partenza, andrai ad inserire uno o più valori intermedi a seconda del dettaglio che vuoi ottenere;
                  3) fai una seconda chiamata [r, k] = rlocus(FDT, k); con il vettore k appena determinato.
                  Il vantaggio, rispetto all’interpolazione, è che i valori che ottieni sono effettivamente punti del luogo.
                  Il metodo più semplice per scegliere i valori da inserire è, ovviamente, l’interpolazione lineare (che nel caso di un solo valore intermedio corrisponde alla media aritmetica). Chiaramente questo metodo non è comunque ottimo, perché potresti sempre generare punti che non ti servono in un segmento, ma sfruttando i valori di partenza forniti da Matlab, ti permette di non strafare.
                  Esempio di interpolazione lineare con un solo nodo intermedio:
                  *** Edit *** Ignora da qui in poi e passa al messaggio successivo
                  `
                  ni = 1; % numero di nodi intermedi tra due adiacenti
                  [r, k] = rlocus(FDT);
                  [r, k] = rlocus(FDT, interp1([k(1:end-1) realmax], 1:1/(ni+1):length(k)));`
                  Aumentando ni, puoi aumentare il numero di nodi intermedi. Nota che interp1 non accetta il valore Inf, che è sempre l’ultimo elemento di k quando calcolato automaticamente. Allora ho sostituito Inf con realmax, che per Matlab è il più grande numero reale. Così facendo, se provi a tracciare il grafico senza indicare manualmente gli assi, probabilmente vedrai qualcosa che non ti convince (ma tanto in pgfplots gli assi li hai indicati quindi non ci sono problemi). Volendo, puoi sostituire realmax con un numero più piccolo, ad esempio un multiplo del penultimo elemento di k: 10*k(end-1).

                  Ciao

                  P.S.: ma ci puoi dire direttamente la funzione di trasferimento?

                • #65280
                  Liverpool
                  Partecipante
                    Up
                    0
                    Down
                    ::


                    Il codice che ti ho scritto alla fine del messaggio precedente non mi convince, perché non posso prevedere il comportamento del luogo quando ci sono zeri al finito e dai valori di k sparisce Inf (magari funziona lo stesso). Per sicurezza, ti indico una variante che si basa sul fatto che, se Matlab passa direttamente da un valore finito all’infinito, probabilmente ritiene che non ci siano variazioni significative in quel tratto:

                    `
                    ni = 1; % numero di nodi intermedi tra due adiacenti
                    [r, k] = rlocus(FDT)
                    [r, k] = rlocus(FDT, [interp1(k(1:end-1), 1:1/(ni+1):length(k)-1) Inf]);
                    `Aumentando ni, puoi aumentare il numero di nodi intermedi.
                    I punti che ottieni in questo modo appartengono sicuramente al luogo delle radici, mentre, interpolando i valori di r, non puoi esserne certo e, quando si analizza la stabilità, bisogna prestare attenzione.
                    Ciao

                    P.S.: Ci puoi dire direttamente la funzione di trasferimento?

                  • #65281
                    Liverpool
                    Partecipante
                      Up
                      0
                      Down
                      ::


                      Il codice che hai scritto nel messaggio 64432 contiene un errore. Con l’istruzione:

                      `
                      \pgfmathsetmacro{\goodrows}{\rows-2}
                      `
                      stai dicendo che il numero di righe da leggere è inferiore di una unità rispetto a quello effettivo della tabella di dati. Quindi, con l’istruzione:

                      `
                      \pgfplotstablegetelem{\goodrows}{\im}\of\datawhead
                      `
                      stai andando a leggere i valori nella penultima riga e li stai prendendo come ordinate degli zeri, ma in realtà non è così. Nel tuo caso, ad esempio, gli zeri al finito si trovano in
                      (-10,\pm 48.26) mentre, con il tuo codice, gli zeri si trovano in (-10,\pm 48.25) e non è detto che l’errore sia sempre così piccolo.

                      L’istruzione corretta è:

                      `
                      \pgfmathsetmacro{\goodrows}{\rows-1}
                      `
                      Tuttavia, se provi a compilare, avrai l’errore che ti avevo segnalato nell’intervento 64416 dovuto alla presenza degli Inf, che pgfplots non accetta. La soluzione consiste nel sostituire tutti gli Inf con dei NaN, che da pgfplots vengono invece riconosciuti ed ignorati. Non so se in pgfplots ci sia un comando per farlo automaticamente (non lo conosco bene), ma di sicuro c’è in Matlab.

                      Nel tuo sorgente, prima di

                      `
                      r_re_im= [real(r)',imag(r)',k'];
                      `
                      inserisci

                      `
                      r(isinf(r))=NaN;
                      `
                      In questo modo sostituirai solo gli Inf di r e non quello di k.

                      Devo anche segnalarti che, siccome la tua tabella non ha una riga di intestazione, la definizione di \datawhead è inutile e tutto quanto ad esso riferito, potrebbe esserlo equivalentemente a \data. Infine ti ricordo che \varpi è già il comando per ottenere una lettera greca, quindi sarebbe meglio utilizzare un altro nome.

                      Ciao

                    • #65282
                      tonegas
                      Partecipante
                        Up
                        0
                        Down
                        ::


                        Grazie a Liverpool e a gli altri ho corretto tutto quello che mi hai detto,
                        appena riesco a dare un migliore layout al grafico aggiungendo un po’ di cose posterò il codice rivisto e corretto.

                    Visualizzazione 10 filoni di risposte
                    • Devi essere connesso per rispondere a questo topic.

                    Go to top