Springen naar inhoud

[matlab] probleem met loops


  • Log in om te kunnen reageren

#1

jppilot

    jppilot


  • >25 berichten
  • 46 berichten
  • Gebruiker

Geplaatst op 17 september 2013 - 20:48

Beste allemaal,

Ik heb een probleem met loops in het programma matlab. Het volgende is de vraag:

%Een compacte weergave van de radarcontacten in de omgeving van het schip is het tactisch plot.
%In dit plot kan in één oogopslag gezien worden wat de classificatie van de verschillende
%contacten is (vriend, vijand, ...) en waar de contacten zich bevinden. Tevens is het identificatie
%nummer van elk contact gegeven. In een modern systeem wordt het tactisch plot op een
%computerbeeldscherm gepresenteerd en is het gekoppeld aan verschillende databases. Hierdoor
%kan bijvoorbeeld snel extra informatie over een contact worden verkregen door erop te klikken.
%Gegeven
%Een lijst (array) van contacten (elke regel is één contact) met identificatienummer (ID, 1ste kolom), x- en y-coördinaten
%(in nm; 2de en 3de kolom) en hun IFF-reeks (4de kolom). In tegenstelling tot voorbeeldopgave D (IFF), is de IFF-reeks
%in deze opgave één getal, bijvoorbeeld 10110, waarbij de opeenvolgende ‘bits’ overeenkomen met modes 1, 2, 3a, 3c en 4.
clear all; clc;
%		  ID X  Y  IFF
INVOER = [1 100 70 00100;	% contact 1, etc.
		   2 100 -60 11000;
		   3 50 100 00110;
		   4 -50 60 00101;
		   5 -50 -100 00110;
		   6 100 40 00010];
A=INVOER(1,4);  
for i =[5:-1:1];
	  IFF1(i)=rem(A,10);  % IFF staat voor identificatie Friend or Foe (vriend of vijand)
	  A =fix(A/10);
	 end;

B=INVOER(2,4);
  for i =[5:-1:1];
	  IFF2(i)=rem(B,10);
	  B =fix(B/10);
  end;
C=INVOER(3,4);
  for i =[5:-1:1];
	  IFF3(i)=rem(C,10);
	  C =fix(C/10);
  end;
D=INVOER(4,4);
  for i =[5:-1:1];
	  IFF4(i)=rem(D,10);
	  D =fix(D/10);
  end;

E=INVOER(5,4);
  for i =[5:-1:1];
	  IFF5(i)=rem(E,10);
	  E =fix(E/10);
  end;
F=INVOER(6,4);
  for i =[5:-1:1];
	  IFF6(i)=rem(F,10);
	  F =fix(F/10);
  end;

IFF = [IFF1;IFF2;IFF3;IFF4;IFF5;IFF6];
CONTACT=IFF;  
for i=1:size(CONTACT,1)
   IFF=decode(CONTACT(i,1),CONTACT(i,2),CONTACT(i,3),CONTACT(i,4),CONTACT(i,5));
   disp(['De IFF van contact ' num2str(i) ' is ' IFF '.'])
end


En de locale functie 'decode':

function [bericht] = decode(mode1,mode2,mode3a,mode3c,mode4)
% Decoder het IFF bericht (zie inleidende tekst in 'IFF')
reeks = [mode1 mode2 mode3a mode3c mode4];
if sum( (reeks==1)|(reeks==0) )~=5
   errordlg('Fout in de IFF-code: niet binair!');   % fout in de code
end
if mode4
   bericht = 'FRIEND';
elseif (mode3a)&(mode3c)
   bericht = 'NEUTRAL';
elseif mode3c % houdt impliet in dat IFF niet mode4 of mode3a bevat
   bericht = 'ASSUMED NEUTRAL';
else
   bericht = 'FOE';
end

Mijn vraag is hoe het gedeelte van:

A=INVOER(1,4);
for i =[5:-1:1];
IFF1(i)=rem(A,10);
A =fix(A/10);
end;

makkelijker gedaan kan worden zodat hij deze berekening voor [:,4] bij invoer doet. Oftewel zodat er ook een lijst aangeleverd kan worden van 4 of 8 rijen. Vervolgens moet er van deze resultaten vanzelf een matrix gegenereerd worden in de trand van: IFF = [IFF1;IFF2;IFF3;IFF4;IFF5;IFF6]; etc naar gelange het aantal IFF's.

Iemand een idee?

Dit forum kan gratis blijven vanwege banners als deze. Door te registeren zal de onderstaande banner overigens verdwijnen.

#2

EvilBro

    EvilBro


  • >5k berichten
  • 6703 berichten
  • VIP

Geplaatst op 18 september 2013 - 13:25

Je zou zoiets kunnen doen:
IFF = mod(fix((INVOER(:,4)*ones(1,5))./(ones(size(INVOER(:,4)))*(10.^[4:-1:0]))),10);
De vraag is natuurlijk of het daar duidelijker van wordt...

#3

jppilot

    jppilot


  • >25 berichten
  • 46 berichten
  • Gebruiker

Geplaatst op 18 september 2013 - 18:17

Nee dat had ik niet zelf kunnen bedenken... Enorm bedankt, zou u deze formule kort kunnen uitleggen?

#4

jppilot

    jppilot


  • >25 berichten
  • 46 berichten
  • Gebruiker

Geplaatst op 18 september 2013 - 19:44

Stapje verder, en weer een vraag waar ik geen oplossing in zie...

De code is nu als volgt:

clear all; clc;
%		  ID X  Y  IFF
INVOER = [1 100 70 00100;	% contact 1, etc.
		   2 100 -60 11000;
		   3 50 100 00110;
		   4 -50 60 00101;
		   5 -50 -100 00110;
		   6 100 40 00010];
	  
IFF1 = mod(fix((INVOER(:,4)*ones(1,5))./(ones(size(INVOER(:,4)))*(10.^[4:-1:0]))),10);
for i=1:size(IFF1,1)
   IFF=decode(IFF1(i,1),IFF1(i,2),IFF1(i,3),IFF1(i,4),IFF1(i,5));
   disp(['De IFF van contact ' num2str(i) ' is ' IFF '.'])
end
[theta,r]=cart2pol(INVOER(:,2),INVOER(:,3)); % omzetten naar polar coordinaten voor alle x en y coordinaten
polar(theta,r,'+')

Vervolgens moet er een polarplot gemaakt worden zoals als volgt, waarbij het getal staat voor het ID, en de symbolen aangeven om wat voor contact het gaat.

Geplaatste afbeelding
greenshot download

Zelf heb ik nu dit, wat logisch volgt uit mijn code. Echter heb ik geen idee hoe ik de code zó moet maken dat het niet uitmaakt hoe groot je invoer is. Ook het teken bij de contacten variabel maken (+. o, driehoek, * ) lukt mij niet.

Geplaatste afbeelding
photo sharing websites

#5

EvilBro

    EvilBro


  • >5k berichten
  • 6703 berichten
  • VIP

Geplaatst op 19 september 2013 - 09:35

Nee dat had ik niet zelf kunnen bedenken... Enorm bedankt, zou u deze formule kort kunnen uitleggen?

Dat zou ik kunnen doen, maar ik denk dat het zinniger is als je zelf een beetje gaat experimenteren. Kijk bijvoorbeeld eens wat delen doen, zoals:
INVOER(:,4)*ones(1,5)
Zo kom je er zelf achter wat er precies gebeurt.

Ik ben overigens van mening dat je je programma verkeerd hebt opgezet. Ik zou hem zo maken dat je aan decode() gewoon het getal kan geven (of een array van getallen) en dat in decode() dit getal ontbonden wordt en omgezet naar de 'kleurcodering' die je nodig hebt voor het commando 'polar'. Informatie over de kleuren en zo kun je op internet wel vinden (bijvoorbeeld hier).

#6

jppilot

    jppilot


  • >25 berichten
  • 46 berichten
  • Gebruiker

Geplaatst op 19 september 2013 - 14:23

Heb je gelijk in, echter mogen we de functie decode() niet aanpassen in het kader van de opdracht :) Bedankt voor de hulp!

#7

EvilBro

    EvilBro


  • >5k berichten
  • 6703 berichten
  • VIP

Geplaatst op 19 september 2013 - 15:05

Mag je wel een extra functie schrijven? Bijvoorbeeld:
function [ ret ] = myDecode (iff)
	bits = mod(fix((iff*ones(1,5))./(10.^[4:-1:0])),10);
	state = decode(bits(1),bits(2),bits(3),bits(4),bits(5));
	switch state
		case 'FRIEND'
			ret = 'b*';
		case 'NEUTRAL'
			ret = 'g+';
		case 'ASSUMED NEUTRAL'
			ret = 'yo';
		case 'FOE'
			ret = 'r^';
		otherwise
			ret = 'k.';
	end
endfunction
Dan kun je iets als dit:
	invoer = [1 100 70 00100;	   % contact 1, etc.
				   2 100 -60 11000;
				   3 50 100 00110;
				   4 -50 60 00101;
				   5 -50 -100 00110;
				   6 100 40 00010];

	figure;
	hold on;
	for i = 1:1:size(invoer,1),
		[t,r] = cart2pol(invoer(i,2:3));
		polar(t,r,myDecode(invoer(i,4)));
	end				  

#8

jppilot

    jppilot


  • >25 berichten
  • 46 berichten
  • Gebruiker

Geplaatst op 19 september 2013 - 20:57

Hm dat was ook een goede oplossing geweest ja. Even geprobeerd en lijkt perfect te werken, snap alleen niet waarom ik tóch een vierkante afbeelding te zien krijg ipv een polar. Raar want de punten worden verder ook niet perfect ingetekend.

clear all; clc;
invoer = [1 100 70 00100;		  % contact 1, etc.
								   2 100 -60 11000;
								   3 50 100 00110;
								   4 -50 60 00101;
								   5 -50 -100 00110;
								   6 100 40 00010];
	    figure;
	    hold on;
	    for i = 1:1:size(invoer,1),
			    [t,r] = cart2pol(invoer(i,2),invoer(i,3));
			    polar(t,r,myDecode(invoer(i,4)));
	    end			 

function [ ret ] = myDecode (iff)
	    bits = mod(fix((iff*ones(1,5))./(10.^[4:-1:0])),10);
	   
	    state = decode(bits(1),bits(2),bits(3),bits(4),bits(5));
	    switch state
			    case 'FRIEND'
					    ret = 'b*';
			    case 'NEUTRAL'
					    ret = 'g+';
			    case 'ASSUMED NEUTRAL'
					    ret = 'yo';
			    case 'FOE'
					    ret = 'r^';
			    otherwise
					    ret = 'k.';
	    end

zelf heb ik het ondertussen opgelost volgens onderstaand:

clear all; clc;
%		  ID X  Y  IFF
INVOER = [1 100 70 00100;    % contact 1, etc.
		   2 100 -60 11000;
		   3 50 100 00110;
		   4 -50 60 00101;
		   5 -50 -100 00110;
		   6 100 40 00010];
	  
IFF1 = mod(fix((INVOER(:,4)*ones(1,5))./(ones(size(INVOER(:,4)))*(10.^[4:-1:0]))),10); % omzetten van binair naar 'losse' enen en nullen.
for i=1:size(IFF1,1)
   IFF=decode(IFF1(i,1),IFF1(i,2),IFF1(i,3),IFF1(i,4),IFF1(i,5));
   [theta,r]=cart2pol(INVOER(i,2),INVOER(i,3)); % omzetten naar polar coordinaten voor alle x en y coordinaten
   if strcmp(IFF,'FOE');
	  polar(theta,r,'^r')
   elseif strcmp(IFF,'NEUTRAL');
	  polar(theta,r,'+g')
   elseif strcmp(IFF,'FRIEND');
	  polar(theta,r,'*b')
   elseif strcmp(IFF,'ASSUMED FRIEND');
	  polar(theta,r,'oc')
   end
   disp(['De IFF van contact ' num2str(i) ' is ' IFF '.'])
   hold on;
end

Toch pittig om dit soort talen te leren. Het voelt alsof je je uren afvraagt hoe je een spijker in de muur kan slaan, om er vervolgens achter te komen dat je gewoon een hamer in je gereedschapskist hebt...

#9

EvilBro

    EvilBro


  • >5k berichten
  • 6703 berichten
  • VIP

Geplaatst op 20 september 2013 - 07:21

Even geprobeerd en lijkt perfect te werken, snap alleen niet waarom ik tóch een vierkante afbeelding te zien krijg ipv een polar.

Ik vermoed dat dit komt omdat ik "figure;hold on" gedaan heb. Ik kan dit echter niet controleren omdat ik Octave gebruik ipv Matlab en het gedrag daar net even anders is. Ik vermoed dat het volgende wel werkt:
clear all; clc;
invoer = [1 100 70 00100;				 % contact 1, etc.
			2 100 -60 11000;
			3 50 100 00110;
			4 -50 60 00101;
			5 -50 -100 00110;
			6 100 40 00010];
			for i = 1:1:size(invoer,1),
							[t,r] = cart2pol(invoer(i,2),invoer(i,3));
							polar(t,r,myDecode(invoer(i,4)));
							hold on;
			end				  

Toch pittig om dit soort talen te leren. Het voelt alsof je je uren afvraagt hoe je een spijker in de muur kan slaan, om er vervolgens achter te komen dat je gewoon een hamer in je gereedschapskist hebt...

Dat klopt. Zeker omdat er al heel veel functies bestaan. Ik heb zelf ook al diverse malen het wiel opnieuw uitgevonden om er vervolgens achter te komen dat het wiel al bestond en nog in een betere vorm ook.

Ik heb toch nog wel een tip over je programmeerstijl. Bekijk mijn programma. Door het opsplitsen in twee functies wordt het geheel overzichtelijker. In het hoofdprogramma kun je heel simpel zien dat de invoer rij voor rij wordt geplot in een polar-diagram. Doordat de conversie van de IFF 'verstopt' zit in myDecode, vertroebelt dit het beeld niet.
Bekijk nu jouw programma. Doordat je al het werk in dezelfde file doet, is het minder makkelijk om snel te zien wat er gebeurt. De grote vraag is bij dat soort code, zeker de oneliner die ik voor je bedacht heb met IFF, of je over een jaar nog weet wat dit ook alweer deed.
Verder is het volgende stukje niet zo mooi:
   if strcmp(IFF,'FOE');
		  polar(theta,r,'^r')
   elseif strcmp(IFF,'NEUTRAL');
		  polar(theta,r,'+g')
   elseif strcmp(IFF,'FRIEND');
		  polar(theta,r,'*b')
   elseif strcmp(IFF,'ASSUMED FRIEND');
		  polar(theta,r,'oc')
   end
Ten eerste denk ik dat een switch-case structuur duidelijker is. Ten tweede doe je voor elke optie eigenlijk hetzelfde. Bij alle opties plot je een polar. Dat de actie bij alle opties eigenlijk hetzelfde is heb je echter verstopt door bij elke optie opnieuw te vertellen wat je gaat doen. Vergelijk dit bijvoorbeeld met:
   pl = '.k';
   if strcmp(IFF,'FOE');
		  pl = '^r';
   elseif strcmp(IFF,'NEUTRAL');
		  pl ='+g';
   elseif strcmp(IFF,'FRIEND');
		  pl ='*b';
   elseif strcmp(IFF,'ASSUMED FRIEND');
		  pl ='oc';
   end
   polar(theta,r,pl)
De omschrijving van dit stukje code is: 'zoek uit welk label het punt heeft en plot dan dat punt.'

#10

Xenion

    Xenion


  • >1k berichten
  • 2606 berichten
  • Moderator

Geplaatst op 20 september 2013 - 17:31

Nog even terzijde:

De code waarmee EvilBro jouw probleem op 1 lijntje oplost is mooi. De filosofie in MATLAB is ook om zoveel mogelijk met matrix-bewerkingen te doen, MATLAB is namelijk geoptimaliseerd om 'vectorized' code uit te voeren.

Het vergt echter veel inzicht in het probleem en in matrix/vector rekening om je code op die manier te kunnen schrijven. Jij bent duidelijk zover nog niet, maar wat je wél zou moeten zien is het repetitieve karakter van je code. Je voert letterlijk 6 keer dezelfde code uit, zij het met andere namen voor variabelen.
Een betere manier zou zijn:
N = size(INVOER,1); % aantal rijen invoer
IFF = zeros(N,5); % pre-alloceer de matrix waar je het resultaat in wegschrijft
for i = 1:N
    % voer hier die repetitieve code uit en schrijf telkens je resultaat naar IFF(i,<img src='http://www.wetenschapsforum.nl/public/style_emoticons/<#EMO_DIR#>/icon_smile.gif' class='bbc_emoticon' alt=':)' />
end

Dat 'pre-alloceren' is een gewoonte die je best aanneemt in MATLAB. Je kan code schrijven waarin je dingen zegt als:
x = 0;
for i = 1:10
    x = [x;0];
end
Bij elke iteratie wordt de vector x langer. Dat betekent dat MATLAB bij elke iteratie een nieuw stuk geheugen moet reserveren en alle oude data daarnaar moet verplaatsen. Als je ooit met grote vectoren werkt, dan zal je merken dat je scripts erg traag worden op deze manier.





0 gebruiker(s) lezen dit onderwerp

0 leden, 0 bezoekers, 0 anonieme gebruikers

Ook adverteren op onze website? Lees hier meer!

Gesponsorde vacatures

Vacatures