diff --git a/src/base.ts b/src/base.ts
index f74f97a4a38d112ac8224622d167b277c5de2fd1..95f88b73cec1aa1c9a65082e35b2e22592df4ff9 100644
--- a/src/base.ts
+++ b/src/base.ts
@@ -1,16 +1,3 @@
-/**
- * Série de valeurs à calculer définie par le nom de la variable à sérier et le vecteur de valeur
- */
-export class Serie {
-    public name: string;
-    public values: number[];
-
-    constructor(name: string, values: number[]) {
-        this.name = name;
-        this.values = values;
-    }
-}
-
 /**
  * Gestion des messages de debogage dans la console
  * @note Etendre cette classe pour toutes les classes à debugguer
diff --git a/src/compute-node.ts b/src/compute-node.ts
index 92c5ec74cf29d8361221c163561d20416a704589..acc5e5b432f2a038355e24a2a00ba525bf24c1d6 100644
--- a/src/compute-node.ts
+++ b/src/compute-node.ts
@@ -1,6 +1,7 @@
 import { Debug } from "./base";
 import { ParamsEquation } from "./param/params-equation";
 import { ParamDefinition } from "./param/param-definition";
+import { ParamValueMode } from "./param/param-values";
 
 /**
  * type de calculette
@@ -51,5 +52,16 @@ export abstract class ComputeNode extends Debug {
         return this._prms.getFirstAnalyticalParameter();
     }
 
+    public initParametersValueMode(computedParam: ParamDefinition, variatedParam?: ParamDefinition, variatedMode?: ParamValueMode) {
+        for (const k in this._prms.map) {
+            if (k == computedParam.symbol)
+                this._prms.map[k].paramValues.valueMode = ParamValueMode.CALCUL;
+            else if (variatedParam && k == variatedParam.symbol)
+                this._prms.map[k].paramValues.valueMode = variatedMode;
+            else
+                this._prms.map[k].paramValues.valueMode = ParamValueMode.SINGLE;
+        }
+    }
+
     protected abstract setParametersCalculability(): void;
 }
diff --git a/src/nub.ts b/src/nub.ts
index 0b3cf86cdd623d8a899530fefb128423709d4700..6ed251bdaa9a0f77a2468aeefcfe08fcf9e1c39b 100644
--- a/src/nub.ts
+++ b/src/nub.ts
@@ -1,7 +1,9 @@
-import { Debug, Serie } from "./base";
+import { Debug } from "./base";
 import { Dichotomie } from "./dichotomie";
 import { ComputeNode } from "./compute-node";
 import { Result } from "./util/result";
+import { ParamValues, ParamValueMode } from "./param/param-values";
+import { ParamDefinition } from ".";
 
 /**
  * Classe abstraite de Noeud de calcul : classe de base pour tous les calculs
@@ -58,13 +60,56 @@ export abstract class Nub extends ComputeNode {
         return res;
     }
 
-    public CalcSerie(svarCalc: string, serie: Serie): Result[] {
-        /** @todo faire une boucle pour appeler this.Calc avec chaque valeur de serie.values
-         *
-         */
-        // let results = [new (Result)];
-        const results = [new Result(0)];
-        return results;
+    public CalcSerie(rPrec: number = 0.001, rInit?: number): Result {
+        const res = new Result();
+        this._result = res;
+
+        let variatedParam: ParamDefinition;
+        let computedParam: ParamDefinition;
+        for (const k in this._prms.map) {
+            const p: ParamDefinition = this._prms.map[k];
+
+            switch (p.valueMode) {
+                case ParamValueMode.LISTE:
+                case ParamValueMode.MINMAX:
+                    if (variatedParam == undefined)
+                        variatedParam = p;
+                    else
+                        throw new Error(`CalcSerie() : il y plusieurs paramètres à varier (au moins ${variatedParam.symbol} et ${p.symbol})`);
+                    break;
+
+                case ParamValueMode.CALCUL:
+                    if (computedParam == undefined)
+                        computedParam = p;
+                    else
+                        throw new Error(`CalcSerie() : il y plusieurs paramètres à calculer (au moins ${computedParam.symbol} et ${p.symbol})`);
+                    break;
+            }
+        }
+
+        if (computedParam == undefined)
+            throw new Error(`CalcSerie() : aucun paramètre à calculer`);
+
+        if (rInit === undefined)
+            rInit = this._prms.map[computedParam.symbol].v;
+
+        if (variatedParam == undefined)
+            this.Calc(computedParam.symbol, rInit, rPrec); // résultat dans this._result
+        else {
+            const res = new Result();
+            variatedParam.paramValues.initIterator();
+            while (variatedParam.paramValues.hasNext) {
+                variatedParam.paramValues.next;
+                this.Calc(computedParam.symbol, rInit, rPrec);  // résultat dans this._result
+                res.addResultElement(this._result.resultElement);
+                res.addLog(this._result.log);
+                if (this._result.ok)
+                    rInit = this._result.resultElement.vCalc;
+            }
+            this._result = res;
+        }
+
+        return this._result;
     }
 
     /**
diff --git a/src/param/param-values.ts b/src/param/param-values.ts
index 266cb51a15ae48ee2491a55ae89b8991cf409825..f05578e86ade4afac04083ec3f9ee5d63402e098 100644
--- a/src/param/param-values.ts
+++ b/src/param/param-values.ts
@@ -82,11 +82,32 @@ export class ParamValueIterator implements IterableIterator<number> {
         }
     }
 
+    public get hasNext(): boolean {
+        switch (this._config) {
+            // valeur fixée
+            case 0:
+                return this._index == 0;
+
+            // min/max
+            case 1:
+                const end = this._reverse ? this._index < this._param.min : this._index > this._param.max;
+                return !end;
+
+            // liste
+            case 2:
+                const i = this._index;
+                return this._index >= this._param.valueList.length;
+
+            default:
+                throw new Error(`ParamValueIterator.hasNext() : erreur interne`);
+        }
+    }
+
     public next(): IteratorResult<number> {
         switch (this._config) {
             // valeur fixée
             case 0:
-                if (this._index == 0)
+                if (this.hasNext)
                     return {
                         done: false,
                         value: this._param.singleValue
@@ -100,8 +121,7 @@ export class ParamValueIterator implements IterableIterator<number> {
             // min/max
             case 1:
                 const res = this._index;
-                const end = this._reverse ? this._index < this._param.min : this._index > this._param.max;
-                if (!end) {
+                if (this.hasNext) {
                     if (this._reverse)
                         this._index -= this._param.step;
                     else
@@ -120,7 +140,7 @@ export class ParamValueIterator implements IterableIterator<number> {
             // liste
             case 2:
                 const i = this._index;
-                if (this._index < this._param.valueList.length) {
+                if (this.hasNext) {
                     const res = this._param.valueList[this._index++];
                     return {
                         done: false,
@@ -182,6 +202,11 @@ export class ParamValues {
      */
     private _valueList: number[];
 
+    /**
+     * itérateur courant
+     */
+    private _iterator: ParamValueIterator;
+
     constructor() {
         this._singleValue = new DefinedNumber();
         this.valueMode = ParamValueMode.CALCUL;
@@ -280,10 +305,47 @@ export class ParamValues {
         this.valueMode = ParamValueMode.LISTE;
     }
 
+    /**
+     * crée un iterateur
+     * @param reverse true si on veut itérer max->min ou depuis la fin de la liste
+     */
     public getValuesIterator(reverse: boolean = false): ParamValueIterator {
         return new ParamValueIterator(this, reverse);
     }
 
+    /**
+     * 
+     * @param reverse prépare un itérateur pour parcourir les valeurs
+     */
+    public initIterator(reverse: boolean = false) {
+        switch (this._valueMode) {
+            case ParamValueMode.LISTE:
+            case ParamValueMode.MINMAX:
+                break;
+
+            default:
+                throw new Error(`ParamValues : mode de valeurs ${ParamValueMode[this._valueMode]} incorrect`);
+        }
+
+        this._iterator = this.getValuesIterator(reverse);
+    }
+
+    /**
+     * @return true si il reste des valeurs à parcourir par l'itérateur courant
+     */
+    public get hasNext(): boolean {
+        return this._iterator.hasNext;
+    }
+
+    /**
+     * fixe la valeur courante à la prochaine valeur à parcourir par l'itérateur courant
+     * @return prochaine valeur à parcourir par l'itérateur courant
+     */
+    public get next(): number {
+        this._singleValue.value = this._iterator.next().value;
+        return this._singleValue.value;
+    }
+
     /**
      * copie des membres
      */
diff --git a/src/remous.ts b/src/remous.ts
index 45070fadac9e71a1cbec3912a644aa88c6b962da..3e02d648b599003609f2de6d1cdec9dd54496e1d 100644
--- a/src/remous.ts
+++ b/src/remous.ts
@@ -9,7 +9,7 @@ import { cLog } from "./util/log";
 import { Message, MessageCode } from "./util/message";
 import { Result } from "./util/result";
 import { ResultElement } from "./util/resultelement";
-import { ParamValueIterator, ParamValues } from ".";
+import { ParamValueIterator, ParamValues, BaseParam } from ".";
 
 export enum MethodeResolution {
     Trapezes, EulerExplicite, RungeKutta4
@@ -563,7 +563,8 @@ export class CourbeRemous extends Nub {
                 `Condition limite aval (${this.prms.Yaval.v}) >= ` +
                 `Hauteur critique (${this.Sn.HautCritique}) : calcul de la partie fluviale à partir de l'aval`);
             this.Dx = this.prms.Dx.v;
-            res = this.calcul(this.prms.Yaval.v, xValues.getValuesIterator(true));
+            xValues.initIterator(true);
+            res = this.calcul(this.prms.Yaval.v, xValues);
             res.insertMessage(new Message(MessageCode.INFO_REMOUS_CALCUL_FLUVIAL));
         } else {
             this.debug(
@@ -597,7 +598,8 @@ export class CourbeRemous extends Nub {
                 ") <= Hauteur critique (" + this.Sn.HautCritique +
                 ") : calcul de la partie torrentielle à partir de l'amont");
             this.Dx = -this.prms.Dx.v;
-            res = this.calcul(this.prms.Yamont.v, xValues.getValuesIterator(false));
+            xValues.initIterator(false);
+            res = this.calcul(this.prms.Yamont.v, xValues);
             res.insertMessage(new Message(MessageCode.INFO_REMOUS_CALCUL_TORRENTIEL));
         } else {
             // this._log.add(new Message(MessageCode.ERROR_REMOUS_PAS_CALCUL_DEPUIS_AMONT));
@@ -815,15 +817,16 @@ export class CourbeRemous extends Nub {
      * Calcul d'une courbe de remous en fluvial ou torrentiel
      * @param YCL Condition limite amont (torrentiel) ou aval (fluvial)
      */
-    private calcul(YCL: number, valueIterator: ParamValueIterator): ResultElement {
+    private calcul(YCL: number, varParam: ParamValues): ResultElement {
         const trY: { [key: number]: number; } = {};
         const res = new ResultElement();
 
         let lastY = YCL;
-        trY[round(valueIterator.next().value, this.prmSect.iPrec.v)] = lastY;
+        trY[round(varParam.next, this.prmSect.iPrec.v)] = lastY;
 
         // Boucle de calcul de la courbe de remous
-        for (const x of valueIterator) {
+        while (varParam.hasNext) {
+            const x = varParam.next;
             // this.debug("lastY " + lastY);
             const rY: Result = this.Calc_Y(lastY);
             // this.debug("calcul : x " + x + " y " + rY.vCalc);