Switch from Garmin Running Power to Stryd?

Hello, I cannot find ignore power in my settings. Is there a step I have to do so I get to choose the metric for power?

Click Actions under the activity timeline chart and choose “Settings”:

Sorry I missed this. Yes you need to capture an FTP and zones for the sport to get power analysis, eFTP etc..

I have recently disabled the Garmin native power so I have my correct Stryd power data on Strava. Is there any way to fix all activities in there so they can be then reimported in invervals? In Garmin Connect I have both power from Garmin and power from Stryd on my activities if it makes sense to try syncing from Garmin?

If the data is in the FIT file, you don’t have to re-import. Open one of the activities, go to Actions - Settings. Under ‘Ignore Power data’ you should find a Power field selector that you can set to the second Power Stream.

Select the Stryd stream and check the box to make it the default one for future activities. Don’t check the Ignore box !!!

If you now bulk-reanalyze older activities, all those with the Stryd power stream should now display that Stryd stream.

2 Likes

The issue is that probably Strava doesn’t save this Stryd power into their fit

You are right about that. Strava only sends out a FIT file with the ‘primary source’. It’s better to use Garmin Connect data because Garmin forwards the original FIT file with all data. Strava also looses L/R balance data and advanced running metrics.
You can have both Strava and Garmin Connect as source. Intervals will take care of de-dupping. It will use the FIT from Garmin Connect and the Activity name and a couple of other things from Strava. You don’t have to be afraid ending up with multiple copies of the same activity, Intervals handles all that for you.

1 Like

I fixed the issue detaching my Strava and connecting the Garmin Connect. It will take a little bit of play with the names of the activities but I already have some filter tables so each activity goes to certain place. I liked the fact that when you modify an activity name in here, it updates on Strava as well. I do not know if it’s gonna be the same with Garmin.

EDIT: I re-connected Strava to get activity names and RPEs as you suggested. Thanks!

Where can I find this setting: I’ve been looking for but I haven’t found it yet…

…I’ve been using stryd before joining intervals, and I’d like to keep stride as the preferred run power metric for training…

Like the post says: Bottom of Activity page Actions-Settings

Found…!

Hello
How do I bulk-reanalyze older activities?
Thanks :slight_smile:

Calendar list view, edit, analyse.

worked well… Thanks

Digging this topic, as I’m trying to extract some power data from a FIT file using Python and I really struggle. Could someone confirm which fields Garmin is using, and if there’s some sample code I could use? I’ve tried using fitparse from FitFile library. Here’s a sample record, I can see a Power metric is that the right one? I’m trying to find out the mean power value of specific work intervals on a workout.

[('timestamp', datetime.datetime(2025, 11, 25, 7, 41, 21)), ('position_lat', 603422636), ('position_long', 39434141), ('distance', 1.67), ('enhanced_speed', 1.67), ('enhanced_altitude', 49.799999999999955), ('unknown_140', 1760), ('vertical_oscillation', 64.0), ('stance_time_percent', None), ('stance_time', 439.0), ('vertical_ratio', 8.3), ('stance_time_balance', None), ('step_length', 770.0), ('unknown_87', 0), ('heart_rate', 110), ('cadence', 65), ('temperature', 24), ('activity_type', 'running'), ('fractional_cadence', 0.0), ('unknown_107', 0), ('unknown_134', None), ('unknown_135', 11), ('unknown_136', 96), ('unknown_137', 100), ('unknown_138', 100), ('unknown_143', 71), ('unknown_144', 110), ('Alpha1', 0.5738840103149414), ('Artifacts', 79.0), ('RespirationRate', 30), ('RRa1_ratio', 0.8984829783439636), ('heartrate_alphaHRV', 108), ('Power', 144), ('Form Power', 60), ('Leg Spring Stiffness', 0.0), ('Cadence', 58), ('Ground Time', 588), ('Vertical Oscillation', 0.0), ('Air Power', 1), ('Stryd Humidity', 50), ('Stryd Temperature', 11), ('Impact Loading Rate', 32)]

You can add pandas for easier Data Frame analysis

import fitparse
import pandas as pd

def fit_to_dataframe(fit_file_path):
    """Convert FIT file to pandas DataFrame for easier analysis"""
    
    fitfile = fitparse.FitFile(fit_file_path)
    
    data = []
    for record in fitfile.get_messages("record"):
        record_dict = {}
        for field in record:
            record_dict[field.name] = field.value
        data.append(record_dict)
    
    df = pd.DataFrame(data)
    
    # Filter to only rows with power data
    if 'Power' in df.columns:
        df['Power'] = pd.to_numeric(df['Power'], errors='coerce')
        df = df.dropna(subset=['Power', 'timestamp'])
        df = df.sort_values('timestamp')
    
    return df

# Usage
df = fit_to_dataframe("your_activity.fit")

# Calculate mean power for entire activity
if 'Power' in df.columns:
    mean_power = df['Power'].mean()
    print(f"Mean Power: {mean_power:.1f}W")

Thanks I can see some records have ‘Power’ data, so it looks I’m on the right track, but when making a script to try to calculate mean power for each lap, it returns ‘None’ for all laps.
Could someone have a look? GPT fails to find me a solution…

import fitparse
import pandas as pd


def fit_records_to_dataframe(fit_file_path):
    fitfile = fitparse.FitFile(fit_file_path)

    records = []
    lap_index = 0

    for msg in fitfile.get_messages():
        if msg.name == "event":
            if msg.get_value("event") == "lap":
                lap_index += 1

        elif msg.name == "record":
            row = {}
            for field in msg:
                row[field.name] = field.value

            row["lap_index"] = lap_index
            records.append(row)

    df = pd.DataFrame(records)

    if 'timestamp' not in df.columns or 'Power' not in df.columns:
        raise ValueError("timestamp ou Power absent des records")

    df['timestamp'] = pd.to_datetime(df['timestamp']).dt.tz_localize(None)
    df['Power'] = pd.to_numeric(df['Power'], errors='coerce')
    df['lap_index'] = pd.to_numeric(df['lap_index'], errors='coerce')

    df = df.dropna(subset=['timestamp', 'Power'])
    df = df.sort_values('timestamp')

    return df


def lire_laps(fit_file_path):
    """Extraction des laps Garmin avec bornes temporelles"""
    
    fitfile = fitparse.FitFile(fit_file_path)
    laps = []

    for i, lap in enumerate(fitfile.get_messages("lap"), start=1):
        start_time = lap.get_value("start_time")
        end_time = lap.get_value("timestamp")
        duration = lap.get_value("total_elapsed_time")

        if start_time and end_time:
            laps.append({
                "lap_num": i,
                "start_time": pd.to_datetime(start_time).tz_localize(None),
                "end_time": pd.to_datetime(end_time).tz_localize(None),
                "duration_s": duration
            })

    return pd.DataFrame(laps)


def calcul_puissance_moyenne_par_lap(df_records, df_laps):
    results = []

    for _, lap in df_laps.iterrows():
        lap_idx = lap['lap_num']  # ici déjà 1-based

        df_lap = df_records[df_records['lap_index'] == lap_idx]

        avg_power = df_lap['Power'].mean() if not df_lap.empty else None

        results.append({
            "Lap": lap['lap_num'],
            "Durée (min)": lap['duration_s'] / 60 if lap['duration_s'] else None,
            "Puissance moyenne (W)": avg_power
        })

    return pd.DataFrame(results)


# =========================
# MAIN
# =========================

if __name__ == "__main__":

    FIT_FILE = "/home/ohmax/hr_drift_analyzer/21084535787_ACTIVITY.fit"

    df_records = fit_records_to_dataframe(FIT_FILE)
    df_laps = lire_laps(FIT_FILE)

    df_resultats = calcul_puissance_moyenne_par_lap(df_records, df_laps)

    print("\nPuissance moyenne recalculée par lap (records Stryd) :")
    print("=" * 65)
    print(df_resultats.round(2).to_string(index=False))
    print("=" * 65)