Add new comment

Equations and algorithm for Reverse Osmosis systems normalization

By Daniel
- Updated 7 months ago
Posted in:

On this page you will find a normalization algorithm that can be built in the PLC or in a SCADA system, therefore eliminating the need of the spreadsheets. This algorithm will deliver the normalized results in three variables: Pressure Drop, Permeability and Salt Passage rate. It also can consider the Concentration Polarization factor for a higher precision.

Normalization is a conversion of operational data that allows the user to compare operation at a specific set of conditions to a reference set of conditions in Reverse Osmosis plants. This allows the user to determine whether changes in flow or rejection are caused by fouling, damage to the membrane, or are just due to different operating conditions: temperature, flow and recovery changes and feed water salinity variations.

The RO normalization equations are described in the ASTM D 4516 (2010) and most membrane manufactures distribute free spreadsheets that have slightly improved calculations over the described in the ASTM.


Water mass transport coefficient (A-Value) and Salt mass transport coefficient (B-value)

RO and NF membranes can be defined by two parameters known in the industry as A and B-values. The


  • A-Value represents the water permeability or the resulting flux from a specific driving pressure. The A-value is directly proportional to the Normalized Permeate Flow, most manufacturers recommend cleaning the membranes when those parameters drop 10% from the stabilized startup reference. A lower A-Value after a few months of operation most likely is an indication of fouling. A-Value is measured in GFD/psi or LMH/bar, in the International System: m²/(m².s.Pa).


  • B-Value is the salt diffusion rate through the membrane. Every salt has it's own B-value for a specific membrane according to it's chemical and physical properties and the Normalization model considers all salts as if they were NaCl. The B-value is directly proportional to the Normalized Salt Rejection, most manufacturers recommend cleaning the modules when those parameters increase 10%. A higher B-Value after a few months of operation might indicate fouling or membrane degradation (abrasion, oxidation, etc...). B-Value is measured in flux units: GFD or LMH, in the International System: m³/(m².s).


Why use permeability and salt diffusion rate and not Normalized Flow and Normalized Rejection?

By using the permeability (A-value) and salt diffusion rate (B-value) we can directly compare different plants and different membranes in the same scale. That's impossible using the ASTM terms since a plant can have a normalized flow of 100m³/h and another of 25m³/h.

The A and B-values are also consistent with membrane datasheets data as described in Equations and algorithm for Reverse Osmosis membranes comparison and scientific papers.


The algorithm

The algorithm below uses the equations provided by the membrane manufactures, it was calibrated for multiple element plant comparisons, for single elements please check Equations and algorithm for Reverse Osmosis membranes comparison.

This algorithm was implemented in Plutocalc Water so if you just need to compare performance you can try this software that works on any computer and also in mobile phones.

The algorithm can also take into consideration (optional) the concentration polarization factor for higher precision (thanks to LG). Please notice that the Concentration Polarization is not part of the ASTM D 4516 equation set.


Source code and equations

This source code was written in JavaScript but it can easily be ported to Java, C or any other language. If you need to see it in action please check the Plutocalc Water application.

/* =============================================================
/   * RO normalization and plant comparison function for JavaScript
	* Developed by Daniel Brooke Peig ([email protected])
	* Version 1.0
	* Copyright (C) 2016  Daniel Brooke Peig
/* =============================================================*/
function ro_normalize(user_inputs){
	//Declare variables

	//Inputs - Declare and import
	//Convert for different user input units in this section
	var	Tf  = user_inputs.Tf; //Temperature (C)
	var	Pf  = user_inputs.Pf; //Feed Pressure (bar)
	var	Pc  = user_inputs.Pc; //Concentrate Pressure (bar)
	var	Pp  = user_inputs.Pp; //Permeate Pressure (bar)
	var	Qp_m3h  = user_inputs.Qp; //Product Flow (m³/h)
	var	Qc_m3h  = user_inputs.Qc; //Concentrate Flow (m³/h)
	var Uf = user_inputs.Uf; //Feed conductivity (micro-siemens/cm)
	var Up = user_inputs.Up; //Feed conductivity (micro-siemens/cm)
	var	Area = user_inputs.Area; //Membrane Area (m²)
	var UsePolFact = user_inputs.UsePolFact; //Use (true) or don't use the polarization factor (false)
	//Calculation variables
	var Cf; //Feed concentration (mg/L as NaCl)
	var Cp; //Permeate concentration (mg/L as NaCl)
	var Rej; //Salt Rejection (%)
	var Qp; //Product flow (m³/s)
	var Qf; //Feed flow (m³/s)
	var Rec; //Recovery (%)
	var Beta; //Concentration polarization factor
	var TCF; //Temperature correction factor
	var CFR; //Average Feed/Concentrate Concentration Factor
	var Cfc; //Average Feed/Concentrate Concentration (mg/L)
	var Ofc; //Average Feed/Concentrate Osmotic Pressure (bar)
	var Op; //Permeate Osmotic Pressure (bar)
	var Pd; //Pressure Drop (bar)
	var NDP; //Net Driving Pressure (bar)
	var A_SI; //Water mass transport coefficient (m/(
	var B_SI; //Salt mass transport coefficient (m/s)
	var A_lmhbar; //Water mass transport coefficient at 25°C (LMH/bar)
	var B_lmh; //Salt mass transport coefficient at 25°C (LMH)
	var SProp; //Solution properties table
	//System variables
	var ErrorLog;
	var user_outputs;
	var incomplete_inputs = false;

	//Data tables
	//Check for invalid inputs (negative or zero)
		) incomplete_inputs = true;
	if(Tf>80) ErrorLog += "Temperature is too high for the current model. Max 80C.<BR>";
	if(Uf>7630) Cf = (0.0000000000801*Math.exp(Math.pow((-50.6458-Math.log(Uf)),2)/112.484)); //Conductivity to mg/L approximation by DOW FILMTEC FTNorm
	if(Uf<=7630) Cf = (7.7E-20*Math.exp(Math.pow((-90.4756-Math.log(Uf)),2)/188.884)); //Conductivity to mg/L approximation by DOW FILMTEC FTNorm
	if(Up>7630) Cp = (0.0000000000801*Math.exp(Math.pow((-50.6458-Math.log(Up)),2)/112.484)); //Conductivity to mg/L approximation by DOW FILMTEC FTNorm
	if(Up<=7630) Cp = (7.7E-20*Math.exp(Math.pow((-90.4756-Math.log(Up)),2)/188.884)); //Conductivity to mg/L approximation by DOW FILMTEC FTNorm
	if(Cf>100000) ErrorLog += "Concentration in the feed is higher than 10%, too much for the current osmotic pressure model.<BR>";
	if(Cp>100000) ErrorLog += "Concentration in the permeate is higher than 10%, too much for the current osmotic pressure model.<BR>";
	Rej = (1-Cp/Cf)*100; //Rejection in %
	Qp = Qp_m3h/3600; //Flow conversion
	Qf = (Qp_m3h+Qc_m3h)/3600; //Flow conversion
	Rec = Qp/Qf*100; //Recovery in %
	if(UsePolFact == true) {Beta = Math.pow(Math.exp(0.75*2*Rec/100/(2-Rec/100)),(1/8));} //Calculation from LG NanoH2O normalization spreadsheet
	else Beta = 1; //If not using the concentration polarization factor
	if(Tf>25)TCF = Math.exp(2640*(1/298-1/(273+Tf))); //Calculation according to DOW FILMTEC FTNorm
	if(Tf<=25)TCF = Math.exp(3020*(1/298-1/(273+Tf))); //Calculation according to DOW FILMTEC FTNorm
	CFR = (Math.log(1/(1-(Rec/100)))/(Rec/100)); //Calculation according to the ASTM D4516
	Cfc = Cf*CFR*Beta; //Average feed/concentrate concentration
	Ofc = 0.0385*Cfc*(Tf + 273.15)/(1000-(Cfc/1000))/14.5038; //Calculation according to DOW FILMTEC FTNorm
	Op = 0.0385*Cp*(Tf + 273.15)/(1000-(Cp/1000))/14.5038;	//Calculation according to DOW FILMTEC FTNorm
	Pd = Pf-Pc; //Differential pressure
	NDP = Pf-Pd/2-Ofc+Op-Pp; //Net Driving Pressure
	A_SI = Qp/(Area*TCF*NDP); //International system: m³/(m²
	B_SI = Cp/(Cfc*TCF*Area/Qp); //International system: m³/(m².s)
	A_lmhbar = A_SI*1000*3600; //Permeability at 25°C unit conversion: L/(m² or LMH/bar
	B_lmh = B_SI*1000*3600; //Permeability at 25°C unit conversion: L/(m².h) or LMH
	//Output the results
	//Convert for different user output units in this section
	if(ErrorLog.length == 0 && incomplete_inputs == false)
		user_outputs = {
			ErrorLog: ErrorLog, //Error Messages
			A: A_lmhbar, //Water mass transport coefficient at 25°C (LMH/bar)
			B: B_lmh, //Salt mass transport coefficient at 25°C (LMH)
			NDP: NDP, //Net Driving Pressure (bar)
			Pd: Pd, //Differetial Pressure (bar)
			Rec: Rec, //Recovery (%)
			Rej: Rej, //Rejection (%)
			Ofc: Ofc, //Average feed/concentrate osmotic pressure
			Cp: Cp, //Permeate TDS
			Cf: Cf, //Feed TDS
			Beta: Beta //Concentration polarization factor
		user_outputs = {
			ErrorLog: ErrorLog,
			A: 0,
			B: 0,
			NDP: 0,
			Pd: 0,
			Rec: 0,
			Rej: 0,
			Ofc: 0,
			Cp: 0,
			Cf: 0,
			Beta: 0,
	return user_outputs;

} //End of the procedure

//Usage example - results should display in the browser console
	var user_inputs =
	Tf: 32,
	Pf: 32,
	Pc: 28,
	Pp: 1,
	Qp: 50,
	Qc: 10,
	Uf: 20000,
	Up: 150,
	Area: 1860,
	UsePolFact: true


The content of this field is kept private and will not be shown publicly.
3 + 5 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.