diff --git a/main.cpp b/main.cpp
index 28fad67d0208275cbe48d4a871a0f7487c2a33a6..31467fdd2c65030b6294fec2caac46ba102440bd 100644
--- a/main.cpp
+++ b/main.cpp
@@ -2,6 +2,7 @@
 #include <complex>
 #include <chrono>
 #include <cmath>
+#include <filesystem>
 
 #include "basicmath.h"
 #include "model.h"
@@ -13,6 +14,8 @@
     #define M_PI 3.14159265358979323846
 #endif
 
+static constexpr char PARA_SWEEP_OUTPUT_DIR[] = "./sweep";
+
 static void printComponants(eis::Model& model)
 {
 	eis::Log(eis::Log::DEBUG)<<"Compnants:";
@@ -29,14 +32,6 @@ static void printComponants(eis::Model& model)
 	}
 }
 
-static void paramSweepCb(std::vector<eis::DataPoint>& data, const std::vector<fvalue>& parameters)
-{
-	static size_t i = 0;
-	++i;
-	if((i & 0x3FF) == 0)
-		std::cout<<'.'<<std::flush;
-}
-
 static void runSweep(const std::string& modelString, eis::Range omega, bool normalize = false,
 					 bool reduce = false, bool hertz = false, bool invert = false, double noise = 0)
 {
@@ -77,19 +72,68 @@ static void runSweep(const std::string& modelString, eis::Range omega, bool norm
 	eis::Log(eis::Log::INFO)<<"time taken: "<<duration.count()<<" us";
 }
 
-static void runParamSweep()
+std::vector<eis::Range> rangesFromParamString(const std::string& parameterString, size_t modelParamCount, size_t steps)
+{
+	std::vector<std::string> tokens = tokenize(parameterString, ',');
+
+	if(tokens.size() != modelParamCount)
+	{
+		eis::Log(eis::Log::ERROR)<<"Model requires "<<modelParamCount<<" parameters but "<<tokens.size()<<" parameters where provided\n";
+		return std::vector<eis::Range>();
+	}
+
+	std::vector<eis::Range> ranges;
+
+	try
+	{
+		for(const std::string& str : tokens)
+		{
+			std::vector<std::string> subtokens = tokenize(str, '-', '\0', '\0', 'e');
+			if(subtokens.size() > 2)
+			{
+				eis::Log(eis::Log::ERROR)<<"a range requires two numbers only "<<str<<" provides "<<subtokens.size()<<" numbers\n";
+				return std::vector<eis::Range>();
+			}
+			else if(subtokens.size() == 1)
+			{
+				ranges.push_back(eis::Range(std::stod(subtokens[0]), std::stod(subtokens[0]), 1, true));
+			}
+			else
+			{
+				ranges.push_back(eis::Range(std::stod(subtokens[0]), std::stod(subtokens[1]), steps, true));
+			}
+		}
+	}
+	catch (const std::invalid_argument& ia)
+	{
+		eis::Log(eis::Log::ERROR)<<ia.what();
+		return std::vector<eis::Range>();
+	}
+	return ranges;
+}
+
+static void paramSweepCb(std::vector<eis::DataPoint>& data, const std::vector<fvalue>& parameters)
+{
+	static size_t i = 0;
+	size_t outputSize = data.size();
+	data = eis::reduceRegion(data);
+	data = eis::rescale(data, outputSize);
+	eis::saveToDisk(data, std::string(PARA_SWEEP_OUTPUT_DIR)+std::string("/")+std::to_string(++i)+".csv");
+	eis::Log(eis::Log::INFO, false)<<'.';
+}
+
+static void runParamSweep(const std::string& modelstr, const eis::Range& omega, const std::string& parameterString, size_t steps)
 {
-	eis::Log(eis::Log::INFO)<<__func__;
-	std::string modelStr("w{20e3}p{1e-7, 0.9}");
+	std::string modelStr(modelstr);
 
 	eis::Model model(modelStr);
 
-	std::vector<eis::Range> parameters;
-	parameters.push_back(eis::Range(1e3, 50e3, 100));
-	parameters.push_back(eis::Range(1e-7, 20e-7, 100));
-	parameters.push_back(eis::Range(0.7, 1.2, 100));
+	std::vector<eis::Range> parameters = rangesFromParamString(parameterString, model.getFlatParametersCount(), steps);
+	if(parameters.empty())
+		return;
 
-	eis::Range omega(0, 1e6, 25);
+	eis::Log(eis::Log::INFO)<<"Saving sweep to "<<PARA_SWEEP_OUTPUT_DIR;
+	std::filesystem::create_directory(PARA_SWEEP_OUTPUT_DIR);
 
 	auto start = std::chrono::high_resolution_clock::now();
 	model.executeParamSweep(parameters, omega, &paramSweepCb);
@@ -115,7 +159,7 @@ int main(int argc, char** argv)
 			runSweep(config.modelStr, config.omegaRange, config.normalize, config.reduce, config.hertz, config.invert, config.noise);
 			break;
 		case MODE_PARAM_SWEEP:
-			runParamSweep();
+			runParamSweep(config.modelStr, config.omegaRange, config.parameterString, config.paramSteps);
 			break;
 	}
 	return 0;
diff --git a/options.h b/options.h
index 4ee02f38b0cdc4b54c1453d894ff0d785a2062e5..a09c2fad293cd191a4918bd65f576901475a86a5 100644
--- a/options.h
+++ b/options.h
@@ -15,7 +15,8 @@ static struct argp_option options[] =
 {
   {"verbose",   'v', 0,      0,  "Show debug messages" },
   {"quiet",     'q', 0,      0,  "only output data" },
-  {"param",     'p', 0,      0,  "select parameter sweep mode" },
+  {"param",     'p', "[STRING]",      0,  "select parameter sweep mode" },
+  {"param",     's', "[COUNT]",      0,  "parameter sweep steps" },
   {"model",      'm', "[STRING]",    0,  "set model string" },
   {"omega",      'o', "[START-END]", 0,  "set omega range" },
   {"omegasteps", 'c', "[COUNT]",     0,  "set omega range steps" },
@@ -38,6 +39,8 @@ struct Config
 {
 	std::string modelStr = "c{1e-6}r{1e3}-r{1e3}";
 	unsigned int mode = MODE_SWEEP;
+	std::string parameterString;
+	size_t paramSteps = 10;
 	eis::Range omegaRange;
 	bool normalize = false;
 	bool reduce = false;
@@ -45,7 +48,7 @@ struct Config
 	bool invert = false;
 	double noise = 0;
 
-	Config(): omegaRange(1, 1001, 1, true)
+	Config(): omegaRange(1, 1e6, 50, true)
 	{}
 };
 
@@ -63,10 +66,11 @@ parse_opt (int key, char *arg, struct argp_state *state)
 		eis::Log::level = eis::Log::DEBUG;
 		break;
 	case 's':
-		config->mode = MODE_SWEEP;
+		config->paramSteps = std::stod(arg);
 		break;
 	case 'p':
 		config->mode = MODE_PARAM_SWEEP;
+		config->parameterString.assign(arg);
 		break;
 	case 'm':
 		config->modelStr.assign(arg);
diff --git a/tokenize.cpp b/tokenize.cpp
index f09da75ba3233d51c0501535cae2281c8d3f9c13..b752e8c6efa1930f79e92664830c1daaacd940de 100644
--- a/tokenize.cpp
+++ b/tokenize.cpp
@@ -1,27 +1,26 @@
 #include "tokenize.h"
 
-std::vector<std::string> tokenize(const std::string& str, const char delim, const char ignBracketStart, const char ignBracketEnd)
+std::vector<std::string> tokenize(const std::string& str, const char delim, const char ignBracketStart, const char ignBracketEnd, const char escapeChar)
 {
-	std::stringstream ss(str);
 	std::vector<std::string> tokens;
 
 	std::string token;
 	size_t bracketCounter = 0;
-	for(char ch : str)
+	for(size_t i = 0; i < str.size(); ++i)
 	{
-		if(ch == delim && bracketCounter == 0)
+		if(str[i] == delim && bracketCounter == 0 && (i == 0 || str[i-1] != escapeChar))
 		{
 			tokens.push_back(token);
 			token.clear();
 		}
 		else
 		{
-			token.push_back(ch);
+			token.push_back(str[i]);
 		}
 
-		if(ignBracketStart == ch)
+		if(ignBracketStart == str[i])
 			++bracketCounter;
-		else if(ignBracketEnd == ch)
+		else if(ignBracketEnd == str[i])
 			--bracketCounter;
 	}
 	if(bracketCounter == 0)
diff --git a/tokenize.h b/tokenize.h
index 5f36a46bfc73ef851a72abb638c739f8c27839cf..637fdf580c588e65d28ad1602b2a6e41be0683a7 100644
--- a/tokenize.h
+++ b/tokenize.h
@@ -3,4 +3,5 @@
 #include <vector>
 #include <sstream>
 
-std::vector<std::string> tokenize(const std::string& str, const char delim = ' ', const char ignBracketStart = '\0', const char ignBracketEnd = '\0');
+std::vector<std::string> tokenize(const std::string& str, const char delim = ' ', const char ignBracketStart = '\0',
+								  const char ignBracketEnd = '\0', const char escapeChar = '\0');