Created
March 30, 2010 19:20
-
-
Save jfhbrook/349475 to your computer and use it in GitHub Desktop.
Soon to be a part of the libtsl repository, this file is used to compare real-world results what the pump affinity laws predict.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% tsl_week_8.m | |
% Written by Joshua Holbrook, week of March 28th 2010 | |
% Since people actually seem to be using this, it's licensed | |
% under the WTFPL (http://sam.zoy.org/wtfpl/). | |
% A little snafu with matlab is that you can't define a function within a | |
% non-function script. So, I wrapped these codes in a function! | |
function tsl_week_8() | |
% Prompt 1: *Using Matlab*, perform a sum of least squares non-linear | |
% power regression for the speed vs. flow rate, pressure drop, & pump | |
% power. | |
% | |
% Prompt 2: *Using Matlab, plot the predicted relation over your range | |
% of data for the flow vs. speed, pressure vs. speed, & power vs. speed | |
% on separate plots. Include on each of the plots the individual data | |
% points (no regression lines) you collected. | |
% | |
% This script explains everything I've done in as much detail as I could | |
% think to. | |
% The following data was inserted via COPY-PASTE WOOO | |
% I should find a good way to read values direct from excel. | |
% (note: xlsread() may be able to do it.) | |
% I could totally do this with python--I wonder how much of a PITA | |
% it would be? | |
% | |
% ANYWAYS | |
% | |
% Think of these as tables, not matrices. No trickery going on! | |
% rpm values for each of the four runs. | |
rpm=[498,498,499,499,500; | |
1102,1103,1104,1105,1109; | |
1736,1737,1740,1746,1750; | |
2505,2509,2512,2524,2532]; | |
% Corresponding flow rates | |
flow=[10.70,8.02,5.28,2.50,0.00; | |
24.25,18.28,12.12,6.11,0.00; | |
38.38,28.65,19.17,9.54,0.00; | |
55.35,41.56,28.00,13.98,0.00]; | |
% Corresponding pressure drops | |
pdrop=[0.2,0.5,0.8,0.8,0.8; | |
1.6,3.4,4.3,4.8,5.0; | |
4.1,8.9,11.1,12.3,12.6; | |
8.6,18.9,23.8,26.1,26.5]; | |
% Corresponding BHP | |
bhp=[0.019,0.019,0.017,0.016,0.014; | |
0.127,0.115,0.099,0.084,0.063; | |
0.436,0.393,0.332,0.261,0.192; | |
1.230,1.099,0.899,0.702,0.494]; | |
% Oh, and we'll want valve settings. You'll see why. | |
valve=[1.00,0.75,0.50,0.25,0.00]; | |
% Now for some curve fitting action! | |
function [a,r2] = curvefitaction(xdata,ydata) | |
% This is where the magic happens. | |
% matlab has a metric butt-ton of optimization functions which may | |
% be used for curve-fitting in one way or another. These include | |
% the really basic fminsearch(), tools from the statistics | |
% toolbox, functions from the optimization toolbox (my favorite) | |
% and even a separate curvefit toolbox! Because the optimization | |
% toolbox seems pretty ubiquitous, and the particular function is | |
% easy to use (imo), I chose to use lsqcurvefit(). Just throwing | |
% out there that many alternatives exist! | |
% | |
% This is how you use lsqcurvefit: | |
[a,r2] = lsqcurvefit(@(a,x) a(1).*x.^a(2),[1.0,2.0],xdata, ydata); | |
% Now for some explanation. This function takes the form: | |
% | |
% aout = lsqcurvefit(function(a,x), a0, x,y) | |
% | |
% a is a vector containing all the values you want to change, a0 is | |
% an initial guess ([1.0,1.5] in my case, for a function | |
% y=1.*x.^1.5) and x is a vector of input values. Naturally, y is | |
% the vector of output data that you're matching to. | |
% | |
% In this particular case, I used what's called an "anonymous | |
% function" so that I don't have to define it elsewhere, but that's | |
% not necessary! For example, I could've defined the function like | |
% so: | |
% | |
% function y = apow(a,x) | |
% y = a(1).*x.^a(2); | |
% end | |
% | |
% and then use it with lsqcurvefit like so: | |
% | |
% lsqcurvefit(@apow,[1.0,1.5], xdata, ydata) | |
% | |
% Naturally, your mileage may vary. | |
% | |
% Another concern is that, when running these, I get the following | |
% message: | |
% | |
% > Optimization terminated: first-order optimality less than | |
% > OPTIONS.TolFun, and no negative/zero curvature detected in | |
% > trust region model. | |
% | |
% My understanding is that this means "everything looks to be in | |
% order, so we're terminating," and as such I'm not too worried. | |
% However, if you're concerned and want to explore changing the | |
% termination defaults, you can learn about how to do this by | |
% typing "help optimset" in the matlab terminal. | |
% | |
% Note that that this function, in its current form, is a | |
% one-liner excepting for comments. Having a function like this | |
% that makes things easy is where matlab really shines! | |
% Unfortunately, writing it yourself can be annoying. | |
end | |
% A function that normalizes the data to the last value in each row. | |
function A = normalize(A) | |
% You could easily just do this, y'know, not as a function, but you | |
% know how I like to complicate things! One handy reason for doing | |
% this is that I can change the baseline for everything without | |
% having to change every line where I use normalize(). | |
% | |
% All I do is divide every table by the bottom-left-most value | |
% in the table. This means I chose the max RPM at 100% flow as my | |
% baseline point (You want to use the same baseline for all values, | |
% and you don't want any zero-values). | |
A=A./A(size(A,1),1); | |
% In some languages, you could use the index -1 to represent the | |
% last value in the array. I like this and I wish I could do that | |
% here! Note, these languages all roll 0-index arrays, | |
% not 1-index matrices. | |
end | |
% Now, we can get some work done! | |
% What are we doing again? Oh, yes: | |
% > Prompt 1: *Using Matlab*, perform a sum of least squares non-linear | |
% > power regression for the speed vs. flow rate, pressure drop, & pump | |
% > power. | |
% | |
% > Prompt 2: *Using Matlab, plot the predicted relation over your range | |
% > of data for the flow vs. speed, pressure vs. speed, & power vs. speed | |
% > on separate plots. Include on each of the plots the individual data | |
% > points (no regression lines) you collected. | |
% x is a range of (normalized) rpms, used for graphing. You'll see it | |
% come up later. I use the same trick as is in normalize() to divide it | |
% by the baseline rpm. This is something you could do separately for | |
% each data set, like I mentioned in the normalize() function. | |
x=linspace(450,2600,100)./rpm(size(rpm,1),1); | |
% Now, we normalize all the data sets, including rpm, since I don't | |
% need rpm_0 anymore. | |
rpm = normalize(rpm); | |
flow = normalize(flow); | |
pdrop = normalize(pdrop); | |
bhp = normalize(bhp); | |
% We'll start with a naive reporting of speed vs. flow rate: | |
% | |
% I used obnoxious formatting stuff for prettier output. | |
% If you don't care about how things look, you can just decide to not | |
% surpress function output, and just read a and r2 that way. | |
fprintf('\nNaive Flow Rate vs Speed:\n=====================\n') | |
[a,r2] = curvefitaction(rpm, flow); | |
fprintf('\n(N/N_0) = %-3.2f * (Q/Q_0)^ %-3.2f \n',a(1),a(2)); | |
fprintf('Residual squared: %-3.2f\n\n',r2); | |
% We also desire to output a graph. | |
% Because of the way I shaped the input data and how matlab expects to | |
% receive its y values as a vector (as an array, it plots them as | |
% different sets against x), I used matlab's reshape() function | |
% to make them 1x20 instead of 4x5. The order's pretty jacked up in my | |
% opinion, but as long as the way matlab reorders everything is | |
% consistent (it should be) I think it'll be okay. | |
figure; | |
% This line plots the lsqcurvefit-generated curve. | |
plot(x, a(1).*x.^a(2),'b-'); | |
hold on; | |
% This line plots the original data points. | |
plot(reshape(rpm,1,[]),reshape(flow,1,[]),'kd'); | |
title('Naive Curve Fit of Flow Rate vs. Speed'); | |
xlabel('rpm/rpmo'); | |
ylabel('Q/Qo'); | |
% Look at this figure. You can see that, unfortunately, that there's | |
% another variable at work here, and in retrospect it should've been | |
% obvious. That variable is valve setting. | |
% | |
% There are multiple ways to get around this issue, but I think the | |
% easiest is to do separate curve fits for each flow rate: | |
% Initializing storage for a and r: | |
a=zeros(size(valve,2),2); | |
r2=zeros(size(valve))'; | |
for i=1:size(valve,2), | |
[a(i,:),r2(i)]=curvefitaction(rpm(:,i),flow(:,i)); | |
end | |
fprintf('\n\n\nFlow Rate vs Speed:\n=====================\n') | |
fprintf('\n%%flow_a(1)__a(2)__|_r^2_\n'); | |
for i=1:size(valve,2), | |
fprintf('%-5.2f %-5.2f %-5.2f | %-1.2e \n',valve(i),a(i,:),r2(i)); | |
end | |
% ...and now that we have that: | |
figure; | |
% Commented here is code that will plot the regression curves, but for | |
% the purposes of the lab it's not useful for anything more than | |
% personal interest. Feel free to un-comment/borrow if you like! | |
% Here, I used meshgrid to make the y matrix. meshgrid is very useful | |
% for vectorizing output, if that's how you like to think about these | |
% kinda things. Others prefer to roll for loops, and with today's | |
% java-driven matlab, this is okay! | |
% Anyway, if you want to understand this, try meshgrid out in | |
% interactive mode to see what it does! | |
%[xgrid,a1grid]=meshgrid(x,a(:,1)); | |
%[xgrid,a2grid]=meshgrid(x,a(:,2)); % matlab, afaik, forces me to do | |
% something with the first output :( | |
%plot(x, a1grid.*xgrid.^a2grid,'b-'); | |
% It turns out plotting is way easy, because Bargar doesn't want the | |
% regression lines! What he wants is the pump affinity law curves! | |
plot(x, x,'b-'); | |
hold on; | |
% This line plots the original data points. | |
plot(reshape(rpm,1,[]),reshape(flow,1,[]),'kd'); | |
title('Flow Rate vs. Speed'); | |
xlabel('rpm/rpmo'); | |
ylabel('Q/Qo'); | |
% At this point, we rinse-and-repeat for the rest of the data sets. | |
% I could've turned this into a function, but whatever. | |
% ==Speed v. p-drop== | |
for i=1:size(valve,2), | |
[a(i,:),r2(i)]=curvefitaction(rpm(:,i),pdrop(:,i)); | |
end | |
fprintf('\n\n\nPressure Drop vs Speed:\n=======================\n') | |
fprintf('\n%%flow_a(1)__a(2)__|_r^2_\n'); | |
for i=1:size(valve,2), | |
fprintf('%-5.2f %-5.2f %-5.2f | %-1.2e \n',valve(i),a(i,:),r2(i)); | |
end | |
figure; | |
%[xgrid,a1grid]=meshgrid(x,a(:,1)); | |
%[xgrid,a2grid]=meshgrid(x,a(:,2)); | |
%plot(x, a1grid.*xgrid.^a2grid,'b-'); | |
plot(x, x.^2.0,'b-'); | |
hold on; | |
plot(reshape(rpm,1,[]),reshape(pdrop,1,[]),'kd'); | |
title('Pressure Drop vs. Speed'); | |
xlabel('rpm/rpmo'); | |
ylabel('dP/dPo'); | |
% ==Speed v. bhp== | |
for i=1:size(valve,2), | |
[a(i,:),r2(i)]=curvefitaction(rpm(:,i),bhp(:,i)); | |
end | |
fprintf('\n\n\nBrake Horsepower vs Speed:\n==========================\n') | |
fprintf('\n%%flow_a(1)__a(2)__|_r^2_\n'); | |
for i=1:size(valve,2), | |
fprintf('%-5.2f %-5.2f %-5.2f | %-1.2e \n',valve(i),a(i,:),r2(i)); | |
end | |
figure; | |
%[xgrid,a1grid]=meshgrid(x,a(:,1)); | |
%[xgrid,a2grid]=meshgrid(x,a(:,2)); | |
%plot(x, a1grid.*xgrid.^a2grid,'b-'); | |
plot(x, x.^3.0,'b-'); | |
hold on; | |
plot(reshape(rpm,1,[]),reshape(bhp,1,[]),'kd'); | |
title('Brake Horsepower vs. Speed'); | |
xlabel('rpm/rpmo'); | |
ylabel('HP/HPo'); | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment