Répondre à la discussion
Affichage des résultats 1 à 3 sur 3

[Projet] Régulateur photovoltaique universel avec suiveur solaire



  1. #1
    CapFlam

    [Projet] Régulateur photovoltaique universel avec suiveur solaire

    Bonjour,

    Voici mon projet perso.
    Je "travaille" sur régulateur photovoltaïque, pouvant fonctionner avec ou sans batterie.
    Le schéma de puissance est relativement simple, il s'agit d'un régulateur linéaire à faibles pertes assisté (ou non) d'un premier étage "hacheur" (ou alim à découpage pour parler plus simplement). J'ai prévu de réaliser la commande à l'aide d'un Raspberry Pi Zéro v1.3, disons que c'est un petit automate ou un micro ordinateur qui consomme moins de 1W. Il faudra lui associer des extensions, certaines réalisées sur-mesure pour ce projet, d'autres plus standard, comme un module horloge.

    Le suivis solaire est de type "prédictif", c'est à dire que la trajectoire du soleil est calculée en considérant la position, l'heure et le jour de l'année.
    Les grandes lignes du programme de calcul de la position du soleil sont écrites (en Python)

    Mon but est à la fois de le réaliser "pour moi" mais aussi pour réaliser un système "libre de droit".
    Pour mon compte personnel, je ne pense pas réaliser la partie suiveur solaire, car je ne possède que 2 modules PV, d'un puissance totale de 90Wc.

    J'ai prévu ce mode de fonctionnement sans découpage pour des applications un peu spécifiques, proches de la radioastronomie amateur, pour ne pas être perturbé du tout par des parasites quelconques.

    Cahier des charges:
    mode de fonctionnement : avec découpage / sans découpage
    utilisation avec batterie plomb 6V, 12V, 24V ou sans batterie
    tension réglable : 2,5 À 30V
    courant disponible : 7,5A
    protection anti marche-arrêt répétitif
    protection en cas de branchement de la batterie à l’envers
    protection contre la décharge profonde
    Fonction d’ajustement MPPT

    -----

    Images attachées Images attachées

  2. #2
    CapFlam

    Re : [Projet] Régulateur photovoltaique universel avec suiveur solaire

    Du coté programme et je répète que c'est pas fini
    le calcul de la position solaire se fait à l'aide de 2 programmes (que je dois associer à un fichier de configuration)

    Ce premier programme calcule la durée du jour ainsi la les variables "lentes" (qui n'évoluent quasiment pas au cours d'une journée de 24h*)

    Code:
    # coding: utf-8
    # la ligne precedente permet de declarer le codage du texte, ce n'est pas un commentaire
    version= "V0.1f+"
    date_version= "16/11/2018 "
    # Programme en Python 3
    # programme en cour d'écriture
    
    # Note de modif:
    # ajouter/modifier la gestion des zones polaires lat_polaire=
    # 
    
    mode= 1
    # la ligne ci-dessus défini le comportement par défaut du progamme
    # mode= 0 # auto    : (à finir) effectue les calculs pour d'autres programmes (aucun affichage)
    # mode= 1 # manuel  : affiche seulement les résultats finaux 
    # mode= 2 # test    : affiche les résultats détaillés pour recherche de bugs
    # mode= 3 # config. : (à faire) enregistre les parametres pour le mode auto
    # mode= 4 # test cfg: (en cours d'écriture)
    # modes suivants pour affichage sur écran 2x16 caratéres 
    # mode=11 # manuel
    # mode=12 # test
    # mode=13 # config.
    tpo= 1.5
    # tpo : tempo pour la lecture sur écran 2x16
    # tpo peut être modifié dans le fichier de configuration
    tpo_min=0.5
    # valeur minimale acceptée pour tpo 
    
    import sys
    import argparse
    parser = argparse.ArgumentParser(description='programme de calcul de la duree du jour')
    # la description est visible lors de l'utilisation de --help
    parser.add_argument("--manu", help="calcul manuel", action="store_true")
    parser.add_argument("--test", help="résultats détaillés", action="store_true")
    parser.add_argument("--conf", help="configuration", action="store_true")
    parser.add_argument("--ecr", help="écran classique", action="store_true")
    parser.add_argument("--lcd", help="écran LCD 2x16", action="store_true")
    parser.add_argument("--ver", help="affiche la version", action="store_true")
    args = parser.parse_args()
    if   args.manu: mode=1
    elif args.test: mode=2
    elif args.conf: mode=3
    if   args.lcd: 
        if mode<10: mode= mode+10
    elif args.ecr:
        if mode>10: mode= mode-10
    elif args.ver:
        if mode<10: print("daylignt", version, "du", date_version)
        else:
            print("daylignt", version)
            print("du", date_version)
        sys.exit(1)
    
    if mode>=1:
        if mode<=10:
            print ("programme de calcul de la duree du jour")
        print ("daylight", version)
    
    # chargement des modules
    import math
    import datetime
    import os.path
    import configparser
    if mode>10: import time
    # parametres:
    pi= math.pi
    jours_annee_siderale=365.256363051
    # Nbres de jours dans une année siderale
    # Année sidérale= 365j 6h 9min 10s selon l'observatoire de Paris Meudon
    #                 365j 6h 9min 9,767 6s en 2000 selon Wikipédia
    Va_rad=2*pi / jours_annee_siderale
    # vitesse angulaire de la terre en rad/jour
    # parametres pour le calcul de l' "air mass" AM:
    # r_eq: rayon équatorial de la terre (km)
    r_eq=6378
    # epp: épaisseur "optique" de l’atmosphère (km)
    epp= 9
    k_atm= r_eq/epp
    
    # chargement du fichier de config *.cfg
    if os.path.isfile("daylight.cfg"):
        cfg_file=1
        # si le fichier "daylight.cfg" existe
        # à modifier mettre le chemain relatif
        # Définition de la Fonction "read_conf()"
        def read_conf ():
            """ Chargement du fichier de configuration """
            conf= "daylight.cfg"
            param = {}
            config = configparser.ConfigParser()
            config.read(conf)
            param["tpo"]= config.get('reglages_programmes', 'tpo')
            param["latitude"]= config.get('cst_locale', 'latitude')
            param["longitude"]=config.get('cst_locale', 'longitude')
            param["j_cfg1"]=config.get('var_impair', 'j_annee')
            param["j_cfg2"]=config.get('var_pair', 'j_annee')
            return param
        params=read_conf()
        tpo       = params["tpo"]
        latitude  = params["latitude"]
        longitude = params["longitude"]
        j_cfg1    = params["j_cfg1"]
        j_cfg2    = params["j_cfg2"]
        # sécurité tempo de lecture trop faible
        if tpo<tpo_min: tpo=tpo_min
        if mode<0:    
            if mode<10: print("...")    
            print("config actuelle")
            if mode>10: time.sleep(tpo)
            print("latitude", latitude)
            print("longitude", longitude)
            if mode>10: time.sleep(tpo)
            if mode in [3,13]:
                if   mode==3: input("écraser config?",x)
                elif mode==13:input("écraser la configuration actuelle?", x)
                if not x in ["oui","O",1]: 
                    mode= mode-2
                    print("annulation")
                else: print("confirmation")
                if mode>10: time.sleep(tpo)        
    else:
        cfg_file=0
        if mode>1:
            if mode<10:
                print("fichier de config non trouvé")
            elif mode<11:
                print("no config file")
    
    if mode>=1:
        x=5
        ok=0
        while ok==0:
            if x<1:
                print("ça va pas, j'arrête")
                sys.exit(2)
                # fin de programme
            latitude=  input("latitude ?")
            longitude= input("longitude?")
            x=x-1
            try:
                latitude=  float(latitude)
                longitude= float(longitude)
                ok=1
            except:
                print("...")
                print("valeur incorectes")
                if mode<10:
                    print("longitude et latitude doivent être uniquement des chiffres")
                    print("une latitude positive pour l'hémisphére Nord")
                else: time.sleep(2*tpo)
            if ok==1:
                if not (-180<latitude<180 and -180<longitude<180):
                    if mode<10: print("longitude et latitude doivent être compris entre -180 et +180")
                    else      : print("-180< Nbre <180")
                    ok=0
    
    latitude=  float(latitude)
    longitude= float(longitude)
    Lat_radian= math.radians(latitude)
    eq_tps_L= 4*longitude 
    # eq_tps_L: décalage (en minute) entre l'heure solaire moyenne et l'heure universelle UTC
    from time import time, gmtime, strftime
    secondes=time()
    gmt= gmtime(secondes)
    j_annee= int(strftime("%j",gmt))
    #calcul jour pair ou impair
    if j_annee%2:
        jpar= "impair"
        if mode>1: print("jour pair")
    else:
        jpar= "pair"
        if mode>1: print("jour impair")
    
    decl_rad= math.asin(0.3978*math.sin(Va_rad*(j_annee-(81-2*math.sin(Va_rad*(j_annee-2))))))
    declinaison= math.degrees(decl_rad)
    # la déclinaison est l'angle formé entre les rayons solaires et la verticale de l'équateur
    ind= -math.tan(decl_rad)*math.tan(Lat_radian)
    # ind: calcul intermédiaire et un indice de la durée nuit/jour
    B= 2*pi*(j_annee-81)/364
    E=-9.87*math.sin(2*B)+7.53*math.cos(B)+1.5*math.sin(B)
    # E: équation du temps: décallage (en minute) entre l'heure solaire vraie et l'heure solaire moyenne 
    
    # dec_gmt_loc= datetime.datetime.now()-strftime("%H",gmt)
    
    if ind>1 or ind<-1:
        lever_gmt=  "non"
        coucher_gmt="non"
        if ind>1:
            dureedujour=0
            midi_sol_gmt="nuit"
        elif ind<-1:
            dureedujour=24
    else:
        dureedujour= 24/pi*math.acos(ind)
        midi_sol_gmt= 12+(E+eq_tps_L)/60
        lever_gmt=    midi_sol_gmt-dureedujour/2
        coucher_gmt=  midi_sol_gmt+dureedujour/2
        # midi_sol_loc= midi_sol_gmt+dec_gmt_loc
    
    if mode>=1:
        if mode<10:
            print ("...")
            if mode>=2:
                print ("paramétres de calcul:")
                print ("année sidérale  =", int(jours_annee_siderale), "jours", "et ...")
                print ("informations fournies par le systéme:")
                print ("heure locale    =", datetime.datetime.now().hour, ":", datetime.datetime.now().minute)
                print ("heure UTC       =", (strftime("%H : %M",gmt)))
            print ("jour de l'année =", j_annee)
            print ("éléments calculés par le programme:")
            if mode>=2:
                print ("jour", jpar)
                print ("Eq du temps  =", E, "minutes")
                print ("eq_tps_L     =", eq_tps_L, "minutes")
                print ("ind =", ind)
                print ("B   =", B)
            print ("délinaison     =", declinaison, "°")
            print ("durée du jour  =", dureedujour, "h")
            if   ind>1: print ("nuit polaire")
            elif ind<-1:print ("jour polaire")
        else :
            time.sleep(tpo)
            if mode>=12:
                print ("info systéme:")
                time.sleep(tpo)
                print ((strftime("%H : %M",gmt), "heure UTC"))
                time.sleep(tpo)
            print ("jour de l'année")
            print (j_annee)
            time.sleep(tpo)
            print ("déclinaison")
            print (round(déclinaison,1))
            time.sleep(tpo)
            print ("durée du jour")
            print (round(dureedujour,2))
            time.sleep(tpo)
        
    if mode>=1:
        if mode<=10:
            print ("Désolé! les heures sont en décimales pour le moment")
            print ("midi solaire à    ", midi_sol_gmt, "heure UTC")
            print ("lever  de soleil à", lever_gmt, "heure UTC")
            print ("couher de soleil à", coucher_gmt, "heure UTC")
            # print ("midi solaire en heure locale:", midi_sol_loc)
    
    if mode>=1: print ("fin de programme")

  3. #3
    CapFlam

    Re : [Projet] Régulateur photovoltaique universel avec suiveur solaire

    Ce 2e programme calcule la position du soleil

    Code:
    # coding: utf-8
    # la ligne precedente permet de declarer le codage du texte, ce n'est pas un commentaire
    version= "v0.1e"
    date_version= "25/11/2018"
    description = "programme de calcul de la position du soleil en temps réel"
    # Programme en Python 3
    # programme en cours d'écriture
    mode= 2
    # la ligne ci-dessus défini le comportement par défaut du progamme
    # mode= 0 # auto    : (à finir) effectue les calculs pour d'autres programmes (aucun affichage)
    # mode= 1 # manuel  : affiche seulement les résultats finaux
    # mode= 2 # test    : affiche les résultats détaillés pour recherche de bugs
    # modes suivants pour affichage sur écran 2x16 caratéres 
    # mode=11 # manuel
    # mode=12 # test
    pas_calc= 15
    # pas_calc: "pas de calcul", durée entre chaque calcul, valeur habituelle: 15 minutes
    # le pas de calcul pourra être modifié dans le fichier de configuration
    pas_calc_min=1
    pas_calc_max=60
    # pas_calc_min et pas_cal_max définissent le minimum et le maximum acceptés dans le fichier de configuration
    cfg_nom= "daylight.cfg"
    #cfg_nom: nom du fichier de configuration
    tpo= 1.5
    # tpo: tempo pour la lecture sur écran 2x16
    
    
    import sys
    import argparse
    parser = argparse.ArgumentParser(description= description)
    # la description est visible lors de l'utilisation de --help
    parser.add_argument("--auto", help="calcul auto (attention dure toute la journée)", action="store_true")
    parser.add_argument("--manu", help="calcul manuel en temps réel", action="store_true")
    parser.add_argument("--test", help="résultats détaillés", action="store_true")
    parser.add_argument("--simul", help="simulation d'une journée", action="store_true")
    parser.add_argument("--once", help="une seule fois", action="store_true")
    parser.add_argument("--adnox", help="jusqu'à la nuit", action="store_true")
    parser.add_argument("--ecr", help="écran classique", action="store_true")
    parser.add_argument("--lcd", help="écran LCD 2x16", action="store_true")
    parser.add_argument("--ver", help="affiche la version", action="store_true")
    args = parser.parse_args()
    if   args.manu: mode=1
    elif args.test: mode=2
    if   args.lcd: 
        if mode<10: mode= mode+10
    elif args.ecr:
        if mode>10: mode= mode-10
    elif args.ver:
        if mode<10: print("solocalise", version, "du", date_version)
        else:
            print("solocalise", version)
            print("du", date_version)
        sys.exit(1)
    
    # import 
    import datetime
    # import math
    import os.path
    from time import time, gmtime, strftime, sleep
    from math import pi, degrees, radians, sin, cos, asin, acos, copysign
    # pi= math.pi
    
    if mode>0:
        if mode<=10:
            print(description)
        print("solocalise", version)
        print("...")
    
    # détermination du jour (pair ou impair) à utiliser pour la configuration 
    secondes=time()
    gmt= gmtime(secondes)
    j_annee= int(strftime("%j",gmt))
    if j_annee%2: 
        if mode>1: print("jour impair")
        j_cfg="[var_impair]"
    else:        
        j_cfg= "[var_pair]"
        if mode>1: print("jour impair")
    
    
    # chargement du fichier de configiguration
    if os.path.isfile(cfg_nom):
        # si le fichier cfg_nom existe
        cfg_file=1
        # à modifier mettre le chemain relatif
        # Définition de la Fonction "read_conf()"
        def read_conf ():
            """ Chargement du fichier de configuration """
            conf= cfg_nom
            param = {}
            config = configparser.ConfigParser()
            config.read(conf)
            param["tpo"]       = config.get('reglages_programmes', 'tpo')
            param["lat_radian"] = config.get('cst_locale', 'lat_radian')
            param["longitude"]  = config.get('cst_locale', 'longitude')
            param["lat_polaire"]= config.get('cst_locale', 'lat_polaire')
            param["k_atm"]      = config.get('cst_locale', 'k_atm')
            param["j_annee_cfg"]=config.get(j_cfg, 'j_annee')
            param["lever_gmt"]  =config.get(j_cfg, 'lever_gmt')
            param["coucher_gmt"]=config.get(j_cfg, 'coucher_gmt')
    
            return param
        params=read_conf()
        tpo       = params["tpo"]
        lat_radian= params["lat_radian"]
        lat_polaire=params["longitude"]
        eq_tps_L  = params["lat_polaire"]
        j_annee_cfg=params["j_annee_cfg"]
        lever_gmt  =params["lever_gmt"]
        coucher_gmt=params["coucher_gmt"]
    
        # gestion des jours/nuits polaires
        if lat_polaire==1:
            if mode>1: 
                if mode<10: print("latitudes polaires")
                else:       print("polar zone")
            if lever_gmt=="nuit" or coucher_gmt=="nuit":
                if lever_gmt != coucher_gmt:
                    cfg_corupt=1
                    if mode>0: print("discordance")
                else:
                    if mode>0:
                     print("nuit polaire")
                    sys.exit(1)
                    # arret "normal" du programme
            elif lever_gmt=="non" or coucher_gmt=="non":
                if lever_gmt != coucher_gmt:
                    cfg_corupt=1
                    if mode>0: print("discordance")
                else:
                    if mode>1:
                        print("jour polaire")
                    lever_gmt=0
                    coucher_gmt=24               
        # vérif des données de config
        # vérif date
        if j_annee_cfg != j_année: 
             cfg_corupt=1
             if mode>0: 
                if mode<10: print("erreur: le fichier de configuration n'est pas à jour")
                if mode>10: print("erreur date cfg")    
        else:
            # vérif données en radians
            if abs(lat_radian)>2*pi or abs(decl_rad)>2*pi:  
                cfg_corupt=1
            # vérif données en heures
            if lever_gmt>24 or coucher_gmt>24:
                cfg_corupt=1
            # vérif du pas de calcul
            if pas_cal < pas_cal_mim:
                pas_cal= pas_cal_min
                if mode<1: 
                    if mode<10: print("fréquence maxi de calcul: 1 calcul pour", pas_cal_mim, "minutes")
                    if mode>10: print("MAX lim f. calc")
            elif pas_cal > pas_cal_mim:
                pas_cal = pas_cal_min
                if mode<1: 
                    if mode<10: print("fréquence mini de calcul: 1 calcul pour", pas_cal_mim, "minutes")
                    if mode>10: print("MIN lim f. calc")
    else:
        if mode>0:
            if mode<10:   
                print("fichier de configuration", cfg_nom ,"non trouvé")
            elif mode<11: 
                print("no config file")
                sleep(3*tpo)
        cfg_corupt=1
    
    
    # provisoire pour les tests
    # 20 novembre
    cfg_corupt=0
    lat_radian = radians(49)
    longitude  =2.52
    decl_radian= radians(-19.8)
    E          = -13.52
    lever_gmt  =8
    coucher_gmt=16.3
    
    if args.simul:
        print("simulation")
    
    # action en cas de détection de coruption du fichier de config:
    if cfg_corupt>0:
        if mode==0: sys.exit(1)
        if mode>0:
            print("annulation prog.")
            sys.exit(1)
            # on verra plus tard pour lancer une reconfiguration
    
    
    eq_tps_L= 4*longitude
    # calculs intermédiaires pour aléger:
    cos_lat= cos(lat_radian)
    sin_lat= sin(lat_radian)
    cos_decl= cos(decl_radian)
    sin_decl= sin(decl_radian)
    
    # initialisation de l'heure
    if not args.simul:
        secondes=time()
        gmt= gmtime(secondes)
        H_gmt= int(strftime("%H",gmt))
        M_gmt= int(strftime("%M",gmt))
        S_gmt= int(strftime("%S",gmt))
        Heure_gmt= H_gmt+M_gmt/60+S_gmt/3600
        if mode>0:
            print("initialisation de l'heure")
            print("heure UTC     :", H_gmt,"h", M_gmt,"mn",S_gmt,"s")
            Heure_sol= Heure_gmt+(E+eq_tps_L)/60
            H_sol= int(Heure_sol)
            M_sol= int(60*(Heure_sol-H_sol))
            print("heure solaire :", H_sol,"h", M_sol,"mn")
            if mode>1:
                print("heure UTC en décimale:", Heure_gmt)
            print("...")
    else:
        Heure_gmt= lever_gmt
        print("simulation à partir de", Heure_gmt, "heures")
    
    
    # initialisation variables
    if Heure_gmt>= lever_gmt: 
        run=1
    else:
        if mode>0: print("le soleil n'est pas lévé")
        print("arret programme")
        sys.exit(1)
    tour=0
    # Calculs répétitifs
    while run:
        if mode>0:
            if not tour: 
                print("calculs répétitifs toutes les", pas_calc, "minute(s)")
                print("...")
            elif tour==1 and args.once:
                sys.exit(1)
            tour= tour+1
            print("calcul n°", tour)
        if not args.simul:
            # recupération de l'heure GMT
            secondes=time()
            gmt= gmtime(secondes)
            H_gmt= int(strftime("%H",gmt))
            M_gmt= int(strftime("%M",gmt))
            S_gmt= int(strftime("%S",gmt))
            Heure_gmt= H_gmt+M_gmt/60+S_gmt/3600
            # Heure_gmt: heure actuelle GMT/UTC décimale
            Heure_NpC= Heure_gmt+pas_calc/60
            # Heure_NpC: heure du nouveau pas de calcul
        Heure_sol= Heure_gmt+(E+eq_tps_L)/60
        Heure_sol_NpC= Heure_sol+pas_calc/60
        # Heure_sol: heure solaire vraie décimale
    
        a_sol_deg= (Heure_sol-12)*15
        a_sol= radians(a_sol_deg)
        a_sol_NpC= radians((Heure_sol_NpC-12)*15)
        # a_sol: angle solaire a ne pas confondre avec la hauteur solaire
    
        hauteur_sol_rad= asin(sin_lat*sin_decl+cos_lat*cos_decl*cos(a_sol))
        hauteur_sol= degrees(hauteur_sol_rad)
        hauteur_sol_NpC= asin(sin_lat*sin_decl+cos_lat*cos_decl*cos(a_sol_NpC))
        # hauteur_sol: hauteur solaire
        
        if a_sol==0: 
            azimut=0
        else:
            if a_sol>0: signe_asol= 1
            if a_sol<0: signe_asol=-1
            azimut= degrees(acos((sin_lat*cos_decl*cos(a_sol)-cos_lat*sin_decl)/cos_decl))*signe_asol
            # azimut
        if mode>0:
            H_sol= int(Heure_sol)
            M_sol= int(60*(Heure_sol-H_sol))
            if args.simul:
                H_gmt= int(Heure_gmt)
                M_gmt= int(60*(Heure_gmt-H_gmt))
                S_gmt= 0
            if mode<10:
                print("heure UTC     :", H_gmt,"h", M_gmt,"mn",S_gmt,"s")
                print("heure solaire :", H_sol,"h", M_sol,"mn")
                if mode>1:
                    print("heure solaire décimale:", Heure_sol)
                    print("angle solaire  :", degrees(a_sol), "°")
                print("hauteur solaire :", hauteur_sol)   
                print("azimut solaire  :", azimut)
                print("...")
        if hauteur_sol<0:
            run=0
            if mode>0:
                if hauteur_sol<0: print("c'est la nuit")
                print("arret programme")
        elif not args.simul: 
            sleep(60*pas_calc)
        else:
            sleep(tpo)
            Heure_gmt= Heure_gmt+pas_calc/60
    sys.exit(1)
    
    
    # angle solaire en degres =(B22-12)*15
    # B22= heure solaire vraie
    # hauteur degres=DEGRES(ASIN(SIN(Lat_radian)*SIN($D8)+COS(Lat_radian)*COS($D8)*COS(RADIANS(B$23))))
    # D8= lat_radian non!!! D8 déclinaison!!!
    # B23=angle solaire en degres
    
    # azimut=Azimut_N_S+DEGRES(ACOS((SIN(Lat_radian)*COS($D8)*COS(RADIANS(B$23))-COS(Lat_radian)*SIN($D8))/COS(RADIANS(B24))))*SIGNE(B$23)
    # B24= hauteur_sol

Discussions similaires

  1. [Programmation] suivi du soleil avec un panneau solaire photovoltaique
    Par Fair dans le forum Électronique
    Réponses: 56
    Dernier message: 20/05/2018, 10h51
  2. Réponses: 7
    Dernier message: 30/10/2015, 15h56
  3. Régulateur Solaire avec module SIM?
    Par Mc2g dans le forum Environnement, développement durable et écologie
    Réponses: 5
    Dernier message: 27/05/2011, 14h27
  4. Projet : Suiveur solaire
    Par opus30 dans le forum Électronique
    Réponses: 7
    Dernier message: 12/11/2009, 00h57