I am working on a boiler project in matlab with a partner. We are still new to this program and are currently working on the proportional control part of the boiler program. As a result we get 3 graphs like we are supposed to but we keep getting a mysterious dip on our center graph as seen below. Any diagnosis to the problem on how we can get rid of the dip is what we have been trying to figure out.
Here is our code:
clear all;
close all;
endtime=60;
time=0;
ResPer=0.05; %declares basic functions
setpoint=7;
flowrate=2.4;
valveposition=0.2;
delay=5;
timeaxis=[1:endtime];
valveaxis=0; %declares arrays related to time and graphing
steamaxis=0;
propconstant=0.25;
RelError=0; %declares arrays regarding the proportional controller
desiredvalve=0.5823;
while time<endtime
%RelError=SteamRelativeError(flowrate, setpoint);
%calculates the Relative Error used in the rest of the function
if (time <= delay)
valveposition=0.75*valveposition+0.25*(desiredvalve-propconstant*RelError);
%deals with the valve position before the time exceeds the delay
%valveaxis(time)=valveposition;
else
valveaxis(time-delay)=0.75*valveposition+0.25*(desiredvalve-propconstant*RelError); %calculates and stores valve position after the delay has been passed
end
RelError=SteamRelativeError(flowrate, setpoint); %calculates the Relative Error used in the rest of the function
time=time+1; %increments time
flowrate=ValvePerToFlowRate(valveposition); %calculates flow rate from valve position
valveaxis(time)=valveposition; %stores temporary valve position
steamaxis(time)=flowrate; %stores steam flow rate
erroraxis(time)=RelError; %stores the Relative Error
end
subplot(3,1,2), plot(timeaxis, valveaxis, 'b'); axis([0 endtime 0.2 0.8]);
xlabel('Time(min)'); ylabel('Valve%');
subplot(3,1,1), plot(timeaxis, steamaxis, 'b'); axis([0 endtime 2
setpoint+2]); xlabel('Time(min)'); ylabel('Steam mass flow rate (lbm/s)');
title('Proportional Constant=0.25'); %graphs functions
subplot(3,1,3), plot(timeaxis, erroraxis, 'b'); axis([0 endtime -0.6 0.2]);
xlabel('Time(min)'); ylabel('Error');
And here are our graphs:
The dip is occurring because you set valveaxis in two difference places. In your if else block you set it to:
valveaxis(time-delay)=0.75*valveposition+0.25*(desiredvalve-propconstant*RelError);
However outside of this block you set it to:
valveaxis(time)=valveposition;
At each time the valveaxis is set using the second equation, only to be overwritten by the first formula delay iterations later. The very last values will not get overwritten since you break at time==60, so valveaxis(54) will be the last value set by the first formula. This is why your dip occurs between the 54th and 55th values.
Related
I have a MATLAB GUI that calls an external function to make a plot (make_ethogram_plot).
The idea would be to have an external figure that is constantly updated with the output value from the figure. Every time the data gets updated it should replot the values, it updates at ~10 Hz. I chose gramm (https://github.com/piermorel/gramm/tree/master/%40gramm) because it is really easy to make a raster plot.
This is the function that gets called. I am having issues to
1) Make it only update in the parent figure with specific name, instead of plotting in the GUI(which is the active figure).
2) Make it not crash. It would open many figures or open or close the same figure at 10 Hz until crashing.
In this configuration, it gives error because it doesn't find g after the first plot. Making g , f, and p1 globals makes it crash (opens every time it gets called)
function make_ethogram_plot(datastructure)
% if the figure doesn't exists create it
if(isempty(findobj(0, 'Name', 'My_gramm_ethogram')))
f=figure('Name', 'My_gramm_ethogram');
p1 = uipanel('Parent',f,'BackgroundColor',[1 1 1],'BorderType','none');
g = gramm('x', datastructure.final_data.frameID, 'color', categorical(datastructure.final_data.behavior));
g.geom_raster();
g.set_parent(p1);
g.draw()
else
% defining f,p1, g here (or having them global) works but crashes
% due to refresh rate
g.update()
end
end
I wrote this code to try to replicate your problem:
function animate_random_data
N = 10000;
data = [cumsum(rand(N,1)),randn(N,1)];
for ii=0:1000
% Plot the data
make_ethogram_plot(data);
drawnow
% Compute new data
data(:,1) = cumsum(rand(N,1));
data(:,2) = randn(N,1);
end
function make_ethogram_plot(data)
fig = findobj(0, 'Name', 'My_gramm_ethogram');
if(isempty(fig))
% If the figure doesn't exists create it
fig = figure('Name', 'My_gramm_ethogram');
ax = axes(fig);
plot(ax,data(:,1),data(:,2));
drawnow
set(ax,'xlimmode','manual','ylimmode','manual');
else
% If it does, update it
line = findobj(fig,'type','line');
set(line,'xdata',data(:,1));
set(line,'ydata',data(:,2));
end
Here, I followed your concept of looking for a named figure window, and creating one if it didn't exist. However, if it does exist, I simply replace the XData and YData property of the line that is already there. This is the fastest way of animating a graph, much faster than deleting the existing plot and creating a new one. After plotting, I use drawnow to update the display. I set XLimMode and YLimMode to manual to prevent re-computation of axes limits and consequent re-drawing of the axes.
The function took 17 seconds to draw all 1000 frames, meaning it's drawing about 60 frames a second. It does not (and should not) crash MATLAB.
You can limit the display rate to 20 frames/sec with drawnow limitrate. It will skip updating the display if the frames come too fast.
I don't know what the gramm/update method does, the class is too complicated to quickly see what is going on, but I dare presume it deletes the axes and creates a new plot from scratch. Not that this should crash MATLAB, it might be worth while to submit a bug report. However, you would probably want to update the figure in the more efficient way, following the method I demonstrated above.
Note that this method can be used to update any of the graphical elements in a plot. For example, I have used this method to animate images.
Recently came across a simple issues that I could not solve on my own. I have a Simulink model that uses a matlab function for some calculations inside the model. The idea is that at some specified moment of time I need to change the voltage of an electric drive. And I need to change it until the rotor’s position reaches another specified value. For instance:
If control_signal == 1; (command to start the execution);
While Angle ~= 180 \\ desired angle is 180;
Control voltage = 5 - 0.1 (5V is the initial value, while the increment of
the voltage change is 0.1)
End
end
So technically what I was thinking will happen, is that the cycle will be executed until the angle of 180 is reached, at some value of the control voltage (for instance 4.6). But when I am running this code, Simulink can’t execute the model. So without any warning or errors, simulation freezes at some stage (when the main condition kicks in). So looks like it can’t process further when the cycle’s execution starts. Can somebody help me with the code? Because the described behaviour of the model during simulation is definitely caused by the above mentioned code.
Thank you in advance.
My guess is you convert the value of the angle expressed in radians to degrees, and you calculate the angle beforehand using trigonometry functions - it will never reach precisely 180 degrees. You should choose some epsilon such that 180 - epsilon is close enough to 180 for your application and use that value as your loop condition.
Also, based on your description of the problem you are trying to solve, sounds like you actually want to check whether the angle is not greater than 180, not if it equals 180.
Also, you are incrementing your voltage incorrectly. Everytime you enter the loop, your control_voltage variable equals 5 - 0.1, which means it's constant and will equal 4.9 no matter how many times you run that loop. This is the correct way:
control_voltage = 5; % initial value
if control_signal == 1; (command to start the execution);
while Angle ~= (180 - epsilon) % some epsilon of your choice
control_voltage = control_voltage - 0.1; % now it's smaller by 0.1 every time the loop is run
end
end
I have the model of a dynamic system in Simulink (I cannot change the programming framework). It can be described as an oscillator subject to periodic oscillations. I am trying to control its motion, in particular, to maximize it (for energy generation).
With latching control (a popular control strategy), the idea is to 'latch', i.e. lock in place, the device when its velocity is 0 for a predefined time, and then release it until its velocity reaches 0 again.
So, what I need to do in Simulink is to output a signal 1 once the velocity signal reaches (or is close to) 0, hold it constant for a time period (at 1), then release it (the signal becomes 0), and repeat the process once the velocity reaches 0 again.
I have found a good blog on holding signals constant in Simulink:
http://blogs.mathworks.com/simulink/2014/08/06/how-do-you-hold-the-value-of-a-signal/
However, in my case, I have two conditions for determining the signal: the magnitude of the velocity and the time within the time period. Now, the problem is that as soon as the period is finished, and the device is released (signal = 0), the velocity is still very small, which could result in an incorrect signal of 1 if an if-loop is used.
I think using an S-function may be the best solution, but then I will have to use a fixed time-step. Are there any Simulink-native solutions for this problem?
I ended up using a Matlab function as a temporary solution, and it is very effective. I have taken inspiration from https://uk.mathworks.com/matlabcentral/answers/11323-hold-true-value-for-finite-length-of-time
u is the velocity signal.
function y = fcn(u,nlatch)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This function is used to determine the latching signal.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Using persistent memory:
persistent tick started sign;
% Initialize variables:
if isempty(tick)
tick = 0;
started = 0;
sign = (u>0);
end
U=0; % no latching
s=(u>0);
if s~=sign
started = 1;
end
if started
if tick<nlatch
tick=tick+1;
U = 1;
else
tick = 0;
started = 0;
sign = s;
end
end
y = U;
end
However, as I mentioned, I have to use a fixed step solver, which is no big deal to me, but it can create problems to other users.
If anyone has a more "Simulink-native" solution, please let me know!
Edit
I have now modified the function: the latching is now applied when there is a change in sign in the velocity signal rather than looking at a small magnitude as earlier on (abs(u)<0.005), which was too case-specific.
A colleague of mine has also found a Simulink-native solution:
However, the Matlab function is faster (less computing intensive) when the same time step is employed. Maybe the least computing-intensive solution is a C S-function.
I am working on a yacht velocity prediction program (VPP) in Simulink (I can't upload the image as I am a new user to this forum, apparently).
Solving the problem requires me to know the apparent wind speed and angle (VA and beta, respectively) in order to obtain the force generated by the sails and hence the net force, acceleration and ultimately speed of the boat. However, VA depends on the boat speed (VS). I tried putting in the initial value of the latter through the integrator block which converts the acceleration into speed but I keep getting the following error inside the "Apparent wind" m-function: "Index expression out of bounds. Attempted to access element 3. The valid range is 1-1.". Note that if I rearrange the model and feed the function with a constant value, say, it will work (although the resultant boat speed will not be physically correct). Listing of the m-function is shown below.
Simplified block diagram:
[VT,gamma] -> Apparent wind -> aero- & hydrodynamics -> force/mass -> acceleration -> 1/s -> VS
function [VA, beta] = fcn(inputs)
% 1 - gamma % true wind heading [deg]
% 2 - VT % true wind speed [kts]
% 3 - VS
%#codegen
% apparent wind angle [deg]
beta=atan(sin(inputs(1)*pi/180)/(cos(inputs(1)*pi/180)+inputs(3)/inputs(2)))/pi*180;
% apparent wind speed [kts]
VA=sin(inputs(1)*pi/180)/sin(beta*pi/180)*inputs(2);
end
EDIT: Please find the attached flowchart of the model now that I can actually upload one.
This might help:
Why is signal dimension not propagated properly when Embedded MATLAB blocks are used in a closed loop at
http://www.mathworks.com/support/solutions/en/data/1-9TQFRN/?product=SL&solution=1-9TQFRN
Good luck.
GM
FFT and changing frequency and vectorizing for loop
Greetings All
I can increase and decrease the frequency of a
signal using the combination of fft and a Fourier series expansion FOR loop in
the code below
but if the signal/array is to large it becomes extremely
slow (an array that's 1x44100 takes about 2 mins to complete) I'm sure
it has to do with the for loop but
I'm not exactly sure how to vectorize it to improve performance. Please note that this will be used with audio signals that are 3 to 6 mins long. The 1x44100 array is only a second and it takes about 2 mins to complete
Any recommendations
%create signal
clear all, clc,clf,tic
x= linspace(0,2*pi,44100)';
%Used in exporting to ycalc audio file make sure in sync with above
freq_orig=1;
freq_new=4
vertoff=0;
vertoffConj=0;
vertoffInv=0;
vertoffInvConj=0;
phaseshift=(0)*pi/180 ; %can use mod to limit to 180 degrees
y=sin(freq_orig*(x));
[size_r,size_c]=size(y);
N=size_r; %to test make 50
T=2*pi;
dt=T/N;
t=linspace(0,T-dt,N)';
phase = 0;
f0 = 1/T; % Exactly, one period
y=(y/max(abs(y))*.8)/2; %make the max amplitude here
C = fft(y)/N; % No semicolon to display output
A = real(C);
B = imag(C)*-1; %I needed to multiply by -1 to get the correct sign
% Single-Sided (f >= 0)
An = [A(1); 2*A(2:round(N/2)); A(round(N/2)+1)];
Bn = [B(1); 2*B(2:round(N/2)); B(round(N/2)+1)];
pmax=N/2;
ycalc=zeros(N,1); %preallocating space for ycalc
w=0;
for p=2:pmax
%
%%1 step) re-create signal using equation
ycalc=ycalc+An(p)*cos(freq_new*(p-1).*t-phaseshift)
+Bn(p)*sin(freq_new*(p-1).*t-phaseshift)+(vertoff/pmax);
w=w+(360/(pmax-1)); %used to create phaseshift
phaseshift=w;
end;
fprintf('\n- Completed in %4.4fsec or %4.4fmins\n',toc,toc/60);
subplot(2,1,1), plot(y),title('Orginal Signal');
subplot(2,1,2),plot(ycalc),title('FFT new signal');
Here's a pic of the plot if some one wants to see the output, which is correct the FOR loop is just really really slow
It appears as though you are basically shifting the signal upwards in the frequency domain, and then your "series expansion" is simply implementing the inverse DFT on the shifted version. As you have seen, the naive iDFT is going to be exceedingly slow. Try changing that entire loop into a call to ifft, and you should be able to get a tremendous speedup.